Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6
authorDavid S. Miller <davem@davemloft.net>
Fri, 24 Jul 2009 02:03:51 +0000 (19:03 -0700)
committerDavid S. Miller <davem@davemloft.net>
Fri, 24 Jul 2009 02:03:51 +0000 (19:03 -0700)
Conflicts:
drivers/net/wireless/iwmc3200wifi/netdev.c
net/wireless/scan.c

1171 files changed:
.gitignore
Documentation/block/data-integrity.txt
Documentation/cgroups/cpusets.txt
Documentation/connector/Makefile
Documentation/connector/cn_test.c
Documentation/connector/connector.txt
Documentation/connector/ucon.c
Documentation/gcov.txt
Documentation/kernel-parameters.txt
Documentation/kmemleak.txt
Documentation/leds-lp3944.txt [new file with mode: 0644]
Documentation/powerpc/booting-without-of.txt
Documentation/powerpc/dts-bindings/4xx/emac.txt [new file with mode: 0644]
Documentation/powerpc/dts-bindings/gpio/gpio.txt [new file with mode: 0644]
Documentation/powerpc/dts-bindings/gpio/led.txt
Documentation/powerpc/dts-bindings/gpio/mdio.txt [new file with mode: 0644]
Documentation/powerpc/dts-bindings/marvell.txt [new file with mode: 0644]
Documentation/powerpc/dts-bindings/phy.txt [new file with mode: 0644]
Documentation/powerpc/dts-bindings/spi-bus.txt [new file with mode: 0644]
Documentation/powerpc/dts-bindings/usb-ehci.txt [new file with mode: 0644]
Documentation/powerpc/dts-bindings/xilinx.txt [new file with mode: 0644]
Documentation/sound/alsa/HD-Audio-Models.txt
Documentation/spi/spidev_test.c
MAINTAINERS
Makefile
arch/alpha/include/asm/percpu.h
arch/arm/Kconfig.debug
arch/arm/configs/s3c2410_defconfig
arch/arm/configs/s3c6400_defconfig
arch/arm/configs/tct_hammer_defconfig
arch/arm/include/asm/page.h
arch/arm/kernel/irq.c
arch/arm/kernel/vmlinux.lds.S
arch/arm/mach-at91/board-sam9g20ek.c
arch/arm/mach-at91/board-sam9rlek.c
arch/arm/mach-omap1/board-nokia770.c
arch/arm/mach-omap1/mailbox.c
arch/arm/mach-omap2/board-rx51-peripherals.c
arch/arm/mach-omap2/gpmc-onenand.c
arch/arm/mach-omap2/id.c
arch/arm/mach-omap2/mailbox.c
arch/arm/mach-omap2/mmc-twl4030.c
arch/arm/mach-s3c2440/mach-mini2440.c
arch/arm/mach-s3c2442/mach-gta02.c
arch/arm/plat-omap/dma.c
arch/arm/plat-omap/gpio.c
arch/arm/plat-omap/include/mach/cpu.h
arch/arm/plat-omap/include/mach/dma.h
arch/arm/plat-omap/include/mach/io.h
arch/arm/plat-omap/iommu.c
arch/arm/plat-omap/sram.c
arch/arm/plat-s3c/Makefile
arch/arm/plat-s3c/include/plat/devs.h
arch/arm/plat-s3c24xx/Makefile
arch/arm/plat-s3c24xx/spi-bus0-gpe11_12_13.c
arch/arm/plat-s3c24xx/spi-bus1-gpg5_6_7.c
arch/frv/Kconfig
arch/frv/include/asm/atomic.h
arch/frv/include/asm/perf_counter.h [new file with mode: 0644]
arch/frv/include/asm/system.h
arch/frv/include/asm/unistd.h
arch/frv/kernel/entry.S
arch/frv/kernel/frv_ksyms.c
arch/frv/lib/Makefile
arch/frv/lib/atomic-ops.S
arch/frv/lib/atomic64-ops.S [new file with mode: 0644]
arch/frv/lib/perf_counter.c [new file with mode: 0644]
arch/ia64/hp/sim/simeth.c
arch/ia64/kernel/esi.c
arch/ia64/kernel/perfmon.c
arch/ia64/kernel/salinfo.c
arch/ia64/kvm/kvm_lib.c
arch/ia64/kvm/process.c
arch/ia64/kvm/vcpu.c
arch/ia64/kvm/vtlb.c
arch/ia64/sn/kernel/io_common.c
arch/mips/Kconfig
arch/mips/Makefile
arch/mips/ar7/Makefile [new file with mode: 0644]
arch/mips/ar7/clock.c [new file with mode: 0644]
arch/mips/ar7/gpio.c [new file with mode: 0644]
arch/mips/ar7/irq.c [new file with mode: 0644]
arch/mips/ar7/memory.c [new file with mode: 0644]
arch/mips/ar7/platform.c [new file with mode: 0644]
arch/mips/ar7/prom.c [new file with mode: 0644]
arch/mips/ar7/setup.c [new file with mode: 0644]
arch/mips/ar7/time.c [new file with mode: 0644]
arch/mips/cavium-octeon/Makefile
arch/mips/cavium-octeon/dma-octeon.c
arch/mips/cavium-octeon/pci-common.c [deleted file]
arch/mips/cobalt/buttons.c
arch/mips/cobalt/lcd.c
arch/mips/cobalt/led.c
arch/mips/cobalt/mtd.c
arch/mips/cobalt/rtc.c
arch/mips/cobalt/serial.c
arch/mips/cobalt/time.c
arch/mips/configs/ar7_defconfig [new file with mode: 0644]
arch/mips/gt64120/wrppmc/serial.c
arch/mips/include/asm/amon.h [new file with mode: 0644]
arch/mips/include/asm/ds1287.h
arch/mips/include/asm/elf.h
arch/mips/include/asm/gcmpregs.h
arch/mips/include/asm/gic.h
arch/mips/include/asm/irq_gt641xx.h
arch/mips/include/asm/mach-ar7/ar7.h [new file with mode: 0644]
arch/mips/include/asm/mach-ar7/gpio.h [new file with mode: 0644]
arch/mips/include/asm/mach-ar7/irq.h [new file with mode: 0644]
arch/mips/include/asm/mach-ar7/prom.h [new file with mode: 0644]
arch/mips/include/asm/mach-ar7/spaces.h [new file with mode: 0644]
arch/mips/include/asm/mach-ar7/war.h [new file with mode: 0644]
arch/mips/include/asm/mach-cobalt/irq.h
arch/mips/include/asm/mach-cobalt/mach-gt64120.h
arch/mips/include/asm/octeon/pci-octeon.h [moved from arch/mips/cavium-octeon/pci-common.h with 52% similarity]
arch/mips/include/asm/page.h
arch/mips/include/asm/reg.h
arch/mips/include/asm/swab.h
arch/mips/include/asm/unistd.h
arch/mips/include/asm/vr41xx/capcella.h
arch/mips/include/asm/vr41xx/giu.h
arch/mips/include/asm/vr41xx/irq.h
arch/mips/include/asm/vr41xx/mpc30x.h
arch/mips/include/asm/vr41xx/pci.h
arch/mips/include/asm/vr41xx/siu.h
arch/mips/include/asm/vr41xx/tb0219.h
arch/mips/include/asm/vr41xx/tb0226.h
arch/mips/include/asm/vr41xx/vr41xx.h
arch/mips/kernel/binfmt_elfo32.c
arch/mips/kernel/cevt-ds1287.c
arch/mips/kernel/cevt-gt641xx.c
arch/mips/kernel/csrc-ioasic.c
arch/mips/kernel/irq-gic.c
arch/mips/kernel/irq-gt641xx.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/smp-cmp.c
arch/mips/kernel/sync-r4k.c
arch/mips/kernel/vpe.c
arch/mips/mti-malta/malta-init.c
arch/mips/mti-malta/malta-int.c
arch/mips/mti-malta/malta-reset.c
arch/mips/pci/Makefile
arch/mips/pci/fixup-capcella.c
arch/mips/pci/fixup-mpc30x.c
arch/mips/pci/fixup-tb0219.c
arch/mips/pci/fixup-tb0226.c
arch/mips/pci/fixup-tb0287.c
arch/mips/pci/msi-octeon.c [moved from arch/mips/cavium-octeon/msi.c with 88% similarity]
arch/mips/pci/ops-vr41xx.c
arch/mips/pci/pci-octeon.c [moved from arch/mips/cavium-octeon/pci.c with 78% similarity]
arch/mips/pci/pci-vr41xx.c
arch/mips/pci/pci-vr41xx.h
arch/mips/pci/pcie-octeon.c [moved from arch/mips/cavium-octeon/pcie.c with 98% similarity]
arch/mips/vr41xx/casio-e55/setup.c
arch/mips/vr41xx/common/bcu.c
arch/mips/vr41xx/common/cmu.c
arch/mips/vr41xx/common/giu.c
arch/mips/vr41xx/common/icu.c
arch/mips/vr41xx/common/init.c
arch/mips/vr41xx/common/irq.c
arch/mips/vr41xx/common/pmu.c
arch/mips/vr41xx/common/rtc.c
arch/mips/vr41xx/common/siu.c
arch/mips/vr41xx/common/type.c
arch/mips/vr41xx/ibm-workpad/setup.c
arch/mn10300/include/asm/unistd.h
arch/mn10300/kernel/entry.S
arch/mn10300/kernel/vmlinux.lds.S
arch/parisc/Kconfig
arch/parisc/include/asm/atomic.h
arch/parisc/include/asm/dma.h
arch/parisc/include/asm/perf_counter.h [new file with mode: 0644]
arch/parisc/include/asm/processor.h
arch/parisc/include/asm/system.h
arch/parisc/include/asm/tlbflush.h
arch/parisc/include/asm/unistd.h
arch/parisc/kernel/cache.c
arch/parisc/kernel/inventory.c
arch/parisc/kernel/irq.c
arch/parisc/kernel/pci-dma.c
arch/parisc/kernel/pci.c
arch/parisc/kernel/processor.c
arch/parisc/kernel/setup.c
arch/parisc/kernel/sys_parisc32.c
arch/parisc/kernel/syscall_table.S
arch/parisc/kernel/time.c
arch/parisc/lib/checksum.c
arch/parisc/lib/memcpy.c
arch/parisc/math-emu/decode_exc.c
arch/parisc/mm/fault.c
arch/parisc/mm/init.c
arch/powerpc/Kconfig
arch/powerpc/boot/.gitignore
arch/powerpc/boot/dts/amigaone.dts
arch/powerpc/boot/dts/mpc8569mds.dts
arch/powerpc/include/asm/cpm1.h
arch/powerpc/include/asm/dma-mapping.h
arch/powerpc/include/asm/highmem.h
arch/powerpc/include/asm/hw_irq.h
arch/powerpc/include/asm/perf_counter.h
arch/powerpc/include/asm/pte-hash64-64k.h
arch/powerpc/include/asm/rtas.h
arch/powerpc/kernel/entry_32.S
arch/powerpc/kernel/head_32.S
arch/powerpc/kernel/of_device.c
arch/powerpc/kernel/process.c
arch/powerpc/kernel/rtas.c
arch/powerpc/kernel/setup_32.c
arch/powerpc/kernel/smp.c
arch/powerpc/kernel/udbg_16550.c
arch/powerpc/mm/Makefile
arch/powerpc/mm/highmem.c [new file with mode: 0644]
arch/powerpc/platforms/44x/warp.c
arch/powerpc/platforms/85xx/mpc85xx_mds.c
arch/powerpc/platforms/85xx/smp.c
arch/powerpc/platforms/85xx/socrates.c
arch/powerpc/platforms/85xx/xes_mpc85xx.c
arch/powerpc/platforms/cell/smp.c
arch/powerpc/platforms/chrp/smp.c
arch/powerpc/platforms/pasemi/setup.c
arch/powerpc/platforms/powermac/setup.c
arch/powerpc/platforms/powermac/smp.c
arch/powerpc/platforms/pseries/smp.c
arch/powerpc/sysdev/mpic.c
arch/powerpc/sysdev/qe_lib/qe.c
arch/s390/include/asm/kvm_host.h
arch/s390/kvm/kvm-s390.c
arch/s390/kvm/priv.c
arch/sh/Kconfig.debug
arch/sh/boards/mach-se/7206/io.c
arch/sh/boards/mach-se/7724/setup.c
arch/sh/configs/migor_defconfig
arch/sh/configs/se7724_defconfig
arch/sh/include/asm/perf_counter.h
arch/sh/include/asm/syscall_32.h
arch/sh/include/mach-se/mach/se7724.h
arch/sh/mm/fault_32.c
arch/sh/mm/tlbflush_64.c
arch/sparc/boot/Makefile
arch/sparc/boot/piggyback_32.c
arch/sparc/boot/piggyback_64.c
arch/sparc/kernel/irq_64.c
arch/sparc/kernel/sys32.S
arch/um/drivers/net_kern.c
arch/um/drivers/slip_kern.c
arch/um/drivers/slirp_kern.c
arch/um/include/asm/dma-mapping.h
arch/x86/Kconfig
arch/x86/include/asm/boot.h
arch/x86/include/asm/pci.h
arch/x86/include/asm/percpu.h
arch/x86/include/asm/perf_counter.h
arch/x86/include/asm/proto.h
arch/x86/kernel/cpu/amd.c
arch/x86/kernel/cpu/common.c
arch/x86/kernel/cpu/mcheck/mce.c
arch/x86/kernel/cpu/perf_counter.c
arch/x86/kernel/dumpstack.c
arch/x86/kernel/e820.c
arch/x86/kernel/pci-dma.c
arch/x86/kernel/setup.c
arch/x86/kernel/setup_percpu.c
arch/x86/kernel/tlb_uv.c
arch/x86/kernel/traps.c
arch/x86/kvm/mmu.c
arch/x86/kvm/paging_tmpl.h
arch/x86/kvm/vmx.c
arch/x86/kvm/x86.c
arch/x86/kvm/x86_emulate.c
arch/x86/lib/delay.c
arch/x86/mm/init.c
arch/x86/mm/init_64.c
arch/x86/mm/pageattr.c
arch/x86/power/cpu.c
arch/xtensa/platforms/iss/network.c
block/Makefile
block/blk-core.c
block/blk-merge.c
block/bsg.c
block/cfq-iosched.c
block/cmd-filter.c [deleted file]
block/elevator.c
block/scsi_ioctl.c
drivers/acpi/pci_root.c
drivers/block/cciss.c
drivers/block/cciss_cmd.h
drivers/block/floppy.c
drivers/char/Kconfig
drivers/char/Makefile
drivers/char/bsr.c
drivers/char/tb0219.c
drivers/char/tty_ldisc.c
drivers/char/vr41xx_giu.c
drivers/clocksource/sh_tmu.c
drivers/connector/cn_proc.c
drivers/connector/cn_queue.c
drivers/connector/connector.c
drivers/edac/amd64_edac.c
drivers/edac/amd64_edac.h
drivers/edac/edac_core.h
drivers/edac/edac_mc_sysfs.c
drivers/edac/mpc85xx_edac.c
drivers/edac/mpc85xx_edac.h
drivers/gpio/Kconfig
drivers/gpio/Makefile
drivers/gpio/pl061.c
drivers/gpio/vr41xx_giu.c [new file with mode: 0644]
drivers/gpu/drm/Kconfig
drivers/gpu/drm/Makefile
drivers/gpu/drm/drm_edid.c
drivers/gpu/drm/i915/Makefile
drivers/gpu/drm/i915/dvo.h
drivers/gpu/drm/i915/dvo_ch7017.c
drivers/gpu/drm/i915/dvo_ch7xxx.c
drivers/gpu/drm/i915/dvo_ivch.c
drivers/gpu/drm/i915/dvo_sil164.c
drivers/gpu/drm/i915/dvo_tfp410.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_debug.c
drivers/gpu/drm/i915/i915_gem_tiling.c
drivers/gpu/drm/i915/i915_irq.c
drivers/gpu/drm/i915/i915_reg.h
drivers/gpu/drm/i915/i915_suspend.c
drivers/gpu/drm/i915/intel_bios.c
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_dp.c [new file with mode: 0644]
drivers/gpu/drm/i915/intel_dp.h [new file with mode: 0644]
drivers/gpu/drm/i915/intel_dp_i2c.c [new file with mode: 0644]
drivers/gpu/drm/i915/intel_drv.h
drivers/gpu/drm/i915/intel_dvo.c
drivers/gpu/drm/i915/intel_hdmi.c
drivers/gpu/drm/i915/intel_i2c.c
drivers/gpu/drm/i915/intel_lvds.c
drivers/gpu/drm/i915/intel_modes.c
drivers/gpu/drm/i915/intel_sdvo.c
drivers/gpu/drm/i915/intel_tv.c
drivers/gpu/drm/radeon/radeon_device.c
drivers/gpu/drm/radeon/radeon_drv.c
drivers/gpu/drm/radeon/radeon_fb.c
drivers/gpu/drm/radeon/radeon_object.c
drivers/gpu/drm/ttm/ttm_bo_util.c
drivers/gpu/drm/ttm/ttm_bo_vm.c
drivers/gpu/drm/ttm/ttm_tt.c
drivers/i2c/busses/Kconfig
drivers/ide/cs5520.c
drivers/ide/ide-acpi.c
drivers/ide/ide-cd.c
drivers/ide/ide-devsets.c
drivers/ide/ide-dma.c
drivers/ide/ide-eh.c
drivers/ide/ide-floppy.c
drivers/ide/ide-io.c
drivers/ide/ide-ioctls.c
drivers/ide/ide-iops.c
drivers/ide/ide-pm.c
drivers/ide/ide-probe.c
drivers/ieee802154/fakehard.c
drivers/input/misc/cobalt_btns.c
drivers/isdn/hysdn/hysdn_net.c
drivers/isdn/i4l/isdn_net.c
drivers/isdn/i4l/isdn_ppp.c
drivers/leds/Kconfig
drivers/leds/Makefile
drivers/leds/leds-alix2.c
drivers/leds/leds-bd2802.c
drivers/leds/leds-cobalt-raq.c
drivers/leds/leds-gpio.c
drivers/leds/leds-lp3944.c [new file with mode: 0644]
drivers/leds/leds-pca9532.c
drivers/lguest/lg.h
drivers/lguest/lguest_user.c
drivers/macintosh/macio_asic.c
drivers/md/dm-exception-store.c
drivers/md/dm-table.c
drivers/md/dm.c
drivers/md/linear.c
drivers/md/md.c
drivers/md/multipath.c
drivers/md/raid0.c
drivers/md/raid1.c
drivers/md/raid10.c
drivers/md/raid5.c
drivers/media/dvb/dvb-core/dvb_net.c
drivers/message/fusion/mptlan.c
drivers/mfd/ezx-pcap.c
drivers/mfd/sm501.c
drivers/misc/sgi-xp/xpnet.c
drivers/mmc/host/mmc_spi.c
drivers/mtd/cmdlinepart.c
drivers/mtd/devices/m25p80.c
drivers/mtd/inftlcore.c
drivers/mtd/maps/integrator-flash.c
drivers/mtd/nand/atmel_nand.c
drivers/mtd/nand/omap2.c
drivers/mtd/nftlcore.c
drivers/net/3c501.c
drivers/net/3c505.c
drivers/net/3c507.c
drivers/net/3c509.c
drivers/net/3c515.c
drivers/net/3c523.c
drivers/net/3c527.c
drivers/net/3c59x.c
drivers/net/7990.c
drivers/net/8139cp.c
drivers/net/8139too.c
drivers/net/82596.c
drivers/net/a2065.c
drivers/net/amd8111e.c
drivers/net/appletalk/cops.c
drivers/net/appletalk/ipddp.c
drivers/net/appletalk/ltpc.c
drivers/net/ariadne.c
drivers/net/arm/am79c961a.c
drivers/net/arm/at91_ether.c
drivers/net/arm/ether1.c
drivers/net/arm/ether3.c
drivers/net/at1700.c
drivers/net/atarilance.c
drivers/net/atp.c
drivers/net/au1000_eth.c
drivers/net/b44.c
drivers/net/benet/Kconfig
drivers/net/benet/be.h
drivers/net/benet/be_ethtool.c
drivers/net/benet/be_main.c
drivers/net/bfin_mac.c
drivers/net/bmac.c
drivers/net/bnx2x.h
drivers/net/bnx2x_hsi.h
drivers/net/bnx2x_link.c
drivers/net/bnx2x_link.h
drivers/net/bnx2x_main.c
drivers/net/bnx2x_reg.h
drivers/net/bonding/bond_3ad.c
drivers/net/bonding/bond_alb.c
drivers/net/bonding/bond_main.c
drivers/net/can/Kconfig
drivers/net/can/sja1000/ems_pci.c
drivers/net/can/sja1000/sja1000.c
drivers/net/cassini.c
drivers/net/cris/eth_v10.c
drivers/net/cs89x0.c
drivers/net/cxgb3/adapter.h
drivers/net/cxgb3/ael1002.c
drivers/net/cxgb3/aq100x.c
drivers/net/cxgb3/common.h
drivers/net/cxgb3/cxgb3_main.c
drivers/net/cxgb3/t3_hw.c
drivers/net/cxgb3/xgmac.c
drivers/net/de600.c
drivers/net/de620.c
drivers/net/declance.c
drivers/net/defxx.c
drivers/net/depca.c
drivers/net/dm9000.c
drivers/net/dm9000.h
drivers/net/dnet.c
drivers/net/dummy.c
drivers/net/e100.c
drivers/net/e1000/e1000.h
drivers/net/e1000/e1000_ethtool.c
drivers/net/e1000/e1000_hw.c
drivers/net/e1000/e1000_hw.h
drivers/net/e1000/e1000_main.c
drivers/net/eepro.c
drivers/net/eexpress.c
drivers/net/enc28j60.c
drivers/net/epic100.c
drivers/net/eql.c
drivers/net/eth16i.c
drivers/net/ewrk3.c
drivers/net/fealnx.c
drivers/net/fec.c
drivers/net/fs_enet/mii-fec.c
drivers/net/gianfar.c
drivers/net/hamachi.c
drivers/net/hamradio/6pack.c
drivers/net/hamradio/baycom_epp.c
drivers/net/hamradio/bpqether.c
drivers/net/hamradio/dmascc.c
drivers/net/hamradio/hdlcdrv.c
drivers/net/hamradio/mkiss.c
drivers/net/hamradio/scc.c
drivers/net/hamradio/yam.c
drivers/net/hp100.c
drivers/net/ibm_newemac/core.c
drivers/net/ibmveth.c
drivers/net/ifb.c
drivers/net/ioc3-eth.c
drivers/net/irda/ali-ircc.c
drivers/net/irda/au1k_ir.c
drivers/net/irda/donauboe.c
drivers/net/irda/irda-usb.c
drivers/net/irda/nsc-ircc.c
drivers/net/irda/pxaficp_ir.c
drivers/net/irda/sa1100_ir.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/isa-skeleton.c
drivers/net/iseries_veth.c
drivers/net/ixgb/ixgb_main.c
drivers/net/ixgbe/ixgbe.h
drivers/net/ixgbe/ixgbe_82598.c
drivers/net/ixgbe/ixgbe_ethtool.c
drivers/net/ixgbe/ixgbe_main.c
drivers/net/ixgbe/ixgbe_type.h
drivers/net/ixp2000/ixpdev.c
drivers/net/jazzsonic.c
drivers/net/jme.c
drivers/net/jme.h
drivers/net/lance.c
drivers/net/lib82596.c
drivers/net/lib8390.c
drivers/net/ll_temac_main.c
drivers/net/loopback.c
drivers/net/lp486e.c
drivers/net/mac89x0.c
drivers/net/macb.c
drivers/net/mace.c
drivers/net/meth.c
drivers/net/mipsnet.c
drivers/net/mlx4/en_tx.c
drivers/net/myri10ge/myri10ge.c
drivers/net/myri_sbus.c
drivers/net/natsemi.c
drivers/net/netx-eth.c
drivers/net/ni5010.c
drivers/net/ni52.c
drivers/net/ni65.c
drivers/net/pci-skeleton.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/smc91c92_cs.c
drivers/net/pcmcia/xirc2ps_cs.c
drivers/net/pcnet32.c
drivers/net/phy/Kconfig
drivers/net/phy/Makefile
drivers/net/phy/bcm63xx.c [new file with mode: 0644]
drivers/net/plip.c
drivers/net/ppp_generic.c
drivers/net/r6040.c
drivers/net/rionet.c
drivers/net/rrunner.c
drivers/net/s2io.c
drivers/net/sb1000.c
drivers/net/sb1250-mac.c
drivers/net/seeq8005.c
drivers/net/sgiseeq.c
drivers/net/sh_eth.c
drivers/net/sis900.c
drivers/net/skfp/skfddi.c
drivers/net/slip.c
drivers/net/smc911x.c
drivers/net/smc9194.c
drivers/net/smc91x.c
drivers/net/sonic.c
drivers/net/starfire.c
drivers/net/sun3_82586.c
drivers/net/sun3lance.c
drivers/net/sunbmac.c
drivers/net/sundance.c
drivers/net/sunhme.c
drivers/net/sunlance.c
drivers/net/sunqe.c
drivers/net/tc35815.c
drivers/net/tlan.c
drivers/net/tokenring/3c359.c
drivers/net/tokenring/ibmtr.c
drivers/net/tokenring/lanstreamer.c
drivers/net/tokenring/olympic.c
drivers/net/tokenring/smctr.c
drivers/net/tokenring/tms380tr.c
drivers/net/tulip/de2104x.c
drivers/net/tulip/dmfe.c
drivers/net/tulip/tulip_core.c
drivers/net/tulip/uli526x.c
drivers/net/tulip/winbond-840.c
drivers/net/tulip/xircom_cb.c
drivers/net/tun.c
drivers/net/typhoon.c
drivers/net/ucc_geth.c
drivers/net/ucc_geth.h
drivers/net/usb/catc.c
drivers/net/usb/hso.c
drivers/net/usb/kaweth.c
drivers/net/usb/pegasus.c
drivers/net/usb/rtl8150.c
drivers/net/usb/usbnet.c
drivers/net/veth.c
drivers/net/via-rhine.c
drivers/net/via-velocity.c
drivers/net/via-velocity.h
drivers/net/virtio_net.c
drivers/net/vxge/vxge-config.c
drivers/net/vxge/vxge-config.h
drivers/net/vxge/vxge-main.c
drivers/net/vxge/vxge-main.h
drivers/net/vxge/vxge-reg.h
drivers/net/vxge/vxge-traffic.h
drivers/net/vxge/vxge-version.h
drivers/net/wan/cycx_x25.c
drivers/net/wan/dlci.c
drivers/net/wan/dscc4.c
drivers/net/wan/farsync.c
drivers/net/wan/hdlc_fr.c
drivers/net/wan/lmc/lmc_main.c
drivers/net/wan/sbni.c
drivers/net/wan/wanxl.c
drivers/net/wan/x25_asy.c
drivers/net/wireless/adm8211.c
drivers/net/wireless/airo.c
drivers/net/wireless/arlan-main.c
drivers/net/wireless/at76c50x-usb.c
drivers/net/wireless/ath/ar9170/main.c
drivers/net/wireless/ath/ar9170/usb.c
drivers/net/wireless/ath/ath5k/ath5k.h
drivers/net/wireless/ath/ath5k/attach.c
drivers/net/wireless/ath/ath5k/base.c
drivers/net/wireless/ath/ath5k/base.h
drivers/net/wireless/ath/ath5k/debug.c
drivers/net/wireless/ath/ath5k/phy.c
drivers/net/wireless/ath/ath5k/qcu.c
drivers/net/wireless/ath/ath5k/reset.c
drivers/net/wireless/ath/ath9k/ath9k.h
drivers/net/wireless/ath/ath9k/beacon.c
drivers/net/wireless/ath/ath9k/debug.c
drivers/net/wireless/ath/ath9k/eeprom.c
drivers/net/wireless/ath/ath9k/hw.c
drivers/net/wireless/ath/ath9k/main.c
drivers/net/wireless/ath/ath9k/recv.c
drivers/net/wireless/ath/ath9k/xmit.c
drivers/net/wireless/ath/regd.c
drivers/net/wireless/atmel.c
drivers/net/wireless/b43/xmit.c
drivers/net/wireless/b43legacy/xmit.c
drivers/net/wireless/hostap/hostap_80211_tx.c
drivers/net/wireless/ipw2x00/ipw2200.c
drivers/net/wireless/ipw2x00/libipw_tx.c
drivers/net/wireless/iwlwifi/iwl-3945.c
drivers/net/wireless/iwlwifi/iwl-4965.c
drivers/net/wireless/iwlwifi/iwl-5000.c
drivers/net/wireless/iwlwifi/iwl-agn.c
drivers/net/wireless/iwlwifi/iwl-calib.c
drivers/net/wireless/iwlwifi/iwl-commands.h
drivers/net/wireless/iwlwifi/iwl-core.c
drivers/net/wireless/iwlwifi/iwl-core.h
drivers/net/wireless/iwlwifi/iwl-debug.h
drivers/net/wireless/iwlwifi/iwl-debugfs.c
drivers/net/wireless/iwlwifi/iwl-dev.h
drivers/net/wireless/iwlwifi/iwl-rx.c
drivers/net/wireless/iwlwifi/iwl-scan.c
drivers/net/wireless/iwlwifi/iwl-tx.c
drivers/net/wireless/iwlwifi/iwl3945-base.c
drivers/net/wireless/iwmc3200wifi/cfg80211.c
drivers/net/wireless/iwmc3200wifi/commands.c
drivers/net/wireless/iwmc3200wifi/commands.h
drivers/net/wireless/iwmc3200wifi/eeprom.c
drivers/net/wireless/iwmc3200wifi/fw.c
drivers/net/wireless/iwmc3200wifi/iwm.h
drivers/net/wireless/iwmc3200wifi/lmac.h
drivers/net/wireless/iwmc3200wifi/main.c
drivers/net/wireless/iwmc3200wifi/netdev.c
drivers/net/wireless/iwmc3200wifi/rx.c
drivers/net/wireless/iwmc3200wifi/sdio.c
drivers/net/wireless/iwmc3200wifi/umac.h
drivers/net/wireless/iwmc3200wifi/wext.c
drivers/net/wireless/libertas/assoc.c
drivers/net/wireless/libertas/dev.h
drivers/net/wireless/libertas/if_cs.c
drivers/net/wireless/libertas/if_sdio.c
drivers/net/wireless/libertas/if_spi.c
drivers/net/wireless/libertas/if_usb.c
drivers/net/wireless/libertas/wext.c
drivers/net/wireless/libertas_tf/main.c
drivers/net/wireless/mac80211_hwsim.c
drivers/net/wireless/mwl8k.c
drivers/net/wireless/netwave_cs.c
drivers/net/wireless/orinoco/Kconfig
drivers/net/wireless/orinoco/Makefile
drivers/net/wireless/orinoco/airport.c
drivers/net/wireless/orinoco/cfg.c [new file with mode: 0644]
drivers/net/wireless/orinoco/cfg.h [new file with mode: 0644]
drivers/net/wireless/orinoco/fw.c
drivers/net/wireless/orinoco/hermes.c
drivers/net/wireless/orinoco/hermes.h
drivers/net/wireless/orinoco/hermes_dld.c
drivers/net/wireless/orinoco/hw.c
drivers/net/wireless/orinoco/hw.h
drivers/net/wireless/orinoco/main.c
drivers/net/wireless/orinoco/main.h
drivers/net/wireless/orinoco/orinoco.h
drivers/net/wireless/orinoco/orinoco_cs.c
drivers/net/wireless/orinoco/orinoco_nortel.c
drivers/net/wireless/orinoco/orinoco_pci.c
drivers/net/wireless/orinoco/orinoco_pci.h
drivers/net/wireless/orinoco/orinoco_plx.c
drivers/net/wireless/orinoco/orinoco_tmd.c
drivers/net/wireless/orinoco/scan.c
drivers/net/wireless/orinoco/scan.h
drivers/net/wireless/orinoco/spectrum_cs.c
drivers/net/wireless/orinoco/wext.c
drivers/net/wireless/p54/Makefile
drivers/net/wireless/p54/eeprom.c [new file with mode: 0644]
drivers/net/wireless/p54/eeprom.h [new file with mode: 0644]
drivers/net/wireless/p54/fwio.c [new file with mode: 0644]
drivers/net/wireless/p54/led.c [new file with mode: 0644]
drivers/net/wireless/p54/lmac.h [new file with mode: 0644]
drivers/net/wireless/p54/main.c [new file with mode: 0644]
drivers/net/wireless/p54/p54.h
drivers/net/wireless/p54/p54common.c [deleted file]
drivers/net/wireless/p54/p54common.h [deleted file]
drivers/net/wireless/p54/p54pci.c
drivers/net/wireless/p54/p54spi.c
drivers/net/wireless/p54/p54usb.c
drivers/net/wireless/p54/txrx.c [new file with mode: 0644]
drivers/net/wireless/prism54/islpci_eth.c
drivers/net/wireless/prism54/islpci_hotplug.c
drivers/net/wireless/ray_cs.c
drivers/net/wireless/rndis_wlan.c
drivers/net/wireless/rt2x00/Kconfig
drivers/net/wireless/rt2x00/Makefile
drivers/net/wireless/rt2x00/rt2400pci.c
drivers/net/wireless/rt2x00/rt2500pci.c
drivers/net/wireless/rt2x00/rt2500usb.c
drivers/net/wireless/rt2x00/rt2800usb.c
drivers/net/wireless/rt2x00/rt2x00.h
drivers/net/wireless/rt2x00/rt2x00crypto.c
drivers/net/wireless/rt2x00/rt2x00dev.c
drivers/net/wireless/rt2x00/rt2x00lib.h
drivers/net/wireless/rt2x00/rt2x00mac.c
drivers/net/wireless/rt2x00/rt2x00rfkill.c [deleted file]
drivers/net/wireless/rt2x00/rt61pci.c
drivers/net/wireless/rt2x00/rt73usb.c
drivers/net/wireless/rtl818x/rtl8180_dev.c
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/wl12xx/Kconfig
drivers/net/wireless/wl12xx/Makefile
drivers/net/wireless/wl12xx/acx.c [deleted file]
drivers/net/wireless/wl12xx/cmd.c [deleted file]
drivers/net/wireless/wl12xx/reg.h
drivers/net/wireless/wl12xx/wl1251.h
drivers/net/wireless/wl12xx/wl1251_acx.c [new file with mode: 0644]
drivers/net/wireless/wl12xx/wl1251_acx.h [moved from drivers/net/wireless/wl12xx/acx.h with 86% similarity]
drivers/net/wireless/wl12xx/wl1251_boot.c [moved from drivers/net/wireless/wl12xx/boot.c with 67% similarity]
drivers/net/wireless/wl12xx/wl1251_boot.h [moved from drivers/net/wireless/wl12xx/boot.h with 78% similarity]
drivers/net/wireless/wl12xx/wl1251_cmd.c [new file with mode: 0644]
drivers/net/wireless/wl12xx/wl1251_cmd.h [moved from drivers/net/wireless/wl12xx/cmd.h with 60% similarity]
drivers/net/wireless/wl12xx/wl1251_debugfs.c [moved from drivers/net/wireless/wl12xx/debugfs.c with 92% similarity]
drivers/net/wireless/wl12xx/wl1251_debugfs.h [moved from drivers/net/wireless/wl12xx/debugfs.h with 74% similarity]
drivers/net/wireless/wl12xx/wl1251_event.c [moved from drivers/net/wireless/wl12xx/event.c with 59% similarity]
drivers/net/wireless/wl12xx/wl1251_event.h [moved from drivers/net/wireless/wl12xx/event.h with 94% similarity]
drivers/net/wireless/wl12xx/wl1251_init.c [moved from drivers/net/wireless/wl12xx/init.c with 55% similarity]
drivers/net/wireless/wl12xx/wl1251_init.h [moved from drivers/net/wireless/wl12xx/init.h with 55% similarity]
drivers/net/wireless/wl12xx/wl1251_main.c [moved from drivers/net/wireless/wl12xx/main.c with 60% similarity]
drivers/net/wireless/wl12xx/wl1251_netlink.c [new file with mode: 0644]
drivers/net/wireless/wl12xx/wl1251_netlink.h [new file with mode: 0644]
drivers/net/wireless/wl12xx/wl1251_ops.c [moved from drivers/net/wireless/wl12xx/wl1251.c with 66% similarity]
drivers/net/wireless/wl12xx/wl1251_ops.h [new file with mode: 0644]
drivers/net/wireless/wl12xx/wl1251_ps.c [moved from drivers/net/wireless/wl12xx/ps.c with 55% similarity]
drivers/net/wireless/wl12xx/wl1251_ps.h [moved from drivers/net/wireless/wl12xx/ps.h with 72% similarity]
drivers/net/wireless/wl12xx/wl1251_rx.c [moved from drivers/net/wireless/wl12xx/rx.c with 68% similarity]
drivers/net/wireless/wl12xx/wl1251_rx.h [moved from drivers/net/wireless/wl12xx/rx.h with 89% similarity]
drivers/net/wireless/wl12xx/wl1251_spi.c [moved from drivers/net/wireless/wl12xx/spi.c with 63% similarity]
drivers/net/wireless/wl12xx/wl1251_spi.h [moved from drivers/net/wireless/wl12xx/spi.h with 61% similarity]
drivers/net/wireless/wl12xx/wl1251_tx.c [moved from drivers/net/wireless/wl12xx/tx.c with 79% similarity]
drivers/net/wireless/wl12xx/wl1251_tx.h [moved from drivers/net/wireless/wl12xx/tx.h with 93% similarity]
drivers/net/wireless/wl12xx/wl12xx.h [deleted file]
drivers/net/wireless/wl3501_cs.c
drivers/net/wireless/zd1201.c
drivers/net/wireless/zd1211rw/zd_mac.c
drivers/net/wireless/zd1211rw/zd_usb.c
drivers/net/xen-netfront.c
drivers/net/xtsonic.c
drivers/net/yellowfin.c
drivers/net/znet.c
drivers/parisc/ccio-dma.c
drivers/parisc/dino.c
drivers/parisc/eisa.c
drivers/parisc/gsc.c
drivers/parisc/gsc.h
drivers/parisc/iosapic.c
drivers/parisc/lba_pci.c
drivers/parisc/sba_iommu.c
drivers/parisc/superio.c
drivers/parport/parport_pc.c
drivers/pci/intel-iommu.c
drivers/pci/iova.c
drivers/pcmcia/vrc4171_card.c
drivers/pcmcia/vrc4173_cardu.c
drivers/pcmcia/vrc4173_cardu.h
drivers/platform/x86/Kconfig
drivers/platform/x86/eeepc-laptop.c
drivers/rtc/rtc-bfin.c
drivers/rtc/rtc-vr41xx.c
drivers/s390/net/claw.c
drivers/s390/net/ctcm_main.c
drivers/s390/net/lcs.c
drivers/s390/net/netiucv.c
drivers/s390/net/qeth_l2_main.c
drivers/s390/net/qeth_l3_main.c
drivers/scsi/cxgb3i/Kbuild
drivers/scsi/cxgb3i/cxgb3i_iscsi.c
drivers/scsi/fnic/fnic_main.c
drivers/scsi/fnic/fnic_scsi.c
drivers/scsi/ibmvscsi/ibmvscsi.c
drivers/scsi/scsi_transport_fc.c
drivers/scsi/sg.c
drivers/scsi/zalon.c
drivers/serial/8250_pci.c
drivers/serial/vr41xx_siu.c
drivers/spi/omap_uwire.c
drivers/spi/spi_bitbang.c
drivers/spi/spidev.c
drivers/ssb/driver_mipscore.c
drivers/staging/agnx/xmit.c
drivers/staging/at76_usb/at76_usb.c
drivers/staging/dst/dcore.c
drivers/staging/epl/VirtualEthernetLinux.c
drivers/staging/otus/usbdrv.c
drivers/staging/otus/wrap_pkt.c
drivers/staging/rt2860/rt_main_dev.c
drivers/staging/rtl8187se/ieee80211/ieee80211_tx.c
drivers/staging/rtl8187se/r8180_core.c
drivers/staging/slicoss/slicoss.c
drivers/staging/stlc45xx/stlc45xx.c
drivers/staging/winbond/wb35rx.c
drivers/staging/wlan-ng/p80211netdev.c
drivers/usb/class/cdc-acm.c
drivers/usb/gadget/f_phonet.c
drivers/usb/gadget/u_ether.c
drivers/usb/serial/usb-serial.c
drivers/video/Kconfig
drivers/video/atafb.c
drivers/video/atmel_lcdfb.c
drivers/video/aty/atyfb.h
drivers/video/aty/atyfb_base.c
drivers/video/aty/mach64_accel.c
drivers/video/backlight/tdo24m.c
drivers/video/cobalt_lcdfb.c
drivers/video/fbmem.c
drivers/video/fsl-diu-fb.c
drivers/video/i810/i810_main.c
drivers/video/matrox/matroxfb_base.c
drivers/video/matrox/matroxfb_crtc2.c
drivers/video/mx3fb.c
drivers/video/omap/omapfb_main.c
drivers/video/platinumfb.c
drivers/video/pxafb.c
drivers/video/sh7760fb.c
drivers/video/sh_mobile_lcdcfb.c
drivers/video/sis/sis_main.c
drivers/video/sm501fb.c
drivers/video/uvesafb.c
drivers/video/w100fb.c
drivers/w1/w1_netlink.c
drivers/watchdog/wdrtas.c
firmware/Makefile
firmware/WHENCE
firmware/cxgb3/ael2005_opt_edc.bin.ihex [new file with mode: 0644]
firmware/cxgb3/ael2005_twx_edc.bin.ihex [new file with mode: 0644]
firmware/cxgb3/ael2020_twx_edc.bin.ihex [new file with mode: 0644]
fs/afs/flock.c
fs/aio.c
fs/binfmt_elf.c
fs/bio-integrity.c
fs/bio.c
fs/btrfs/async-thread.c
fs/btrfs/ctree.h
fs/btrfs/extent-tree.c
fs/btrfs/file.c
fs/btrfs/inode.c
fs/btrfs/ioctl.c
fs/btrfs/relocation.c
fs/btrfs/transaction.c
fs/cifs/CHANGES
fs/cifs/asn1.c
fs/cifs/cifsfs.c
fs/cifs/cifsglob.h
fs/cifs/cifsproto.h
fs/cifs/cifssmb.c
fs/cifs/connect.c
fs/cifs/dir.c
fs/cifs/dns_resolve.c
fs/cifs/file.c
fs/cifs/inode.c
fs/cifs/link.c
fs/cifs/netmisc.c
fs/cifs/sess.c
fs/cifs/xattr.c
fs/dlm/netlink.c
fs/eventfd.c
fs/ext2/namei.c
fs/fuse/dev.c
fs/fuse/dir.c
fs/fuse/file.c
fs/fuse/fuse_i.h
fs/fuse/inode.c
fs/hostfs/hostfs_kern.c
fs/jffs2/scan.c
fs/namei.c
fs/nfsd/vfs.c
fs/notify/inotify/inotify_user.c
include/asm-generic/percpu.h
include/asm-generic/vmlinux.lds.h
include/drm/drm_edid.h
include/linux/aio.h
include/linux/bio.h
include/linux/blkdev.h
include/linux/connector.h
include/linux/eventfd.h
include/linux/fb.h
include/linux/fsnotify_backend.h
include/linux/fuse.h
include/linux/hrtimer.h
include/linux/ide.h
include/linux/ieee80211.h
include/linux/if_tun.h
include/linux/ima.h
include/linux/init_task.h
include/linux/kernel.h
include/linux/kvm_host.h
include/linux/leds-lp3944.h [new file with mode: 0644]
include/linux/leds.h
include/linux/linkage.h
include/linux/mm.h
include/linux/net_dropmon.h
include/linux/netdevice.h
include/linux/nl80211.h
include/linux/pci_ids.h
include/linux/percpu-defs.h
include/linux/perf_counter.h
include/linux/rfkill.h
include/linux/sched.h
include/linux/spi/spi.h
include/linux/spi/spidev.h
include/linux/timer.h
include/linux/tipc.h
include/linux/usb/usbnet.h
include/linux/wireless.h
include/net/cfg80211.h
include/net/genetlink.h
include/net/ipv6.h
include/net/iw_handler.h
include/net/mac80211.h
include/net/net_namespace.h
include/net/netns/x_tables.h
include/net/phonet/pn_dev.h
include/net/scm.h
include/net/udp.h
ipc/mqueue.c
kernel/Makefile
kernel/acct.c
kernel/futex.c
kernel/perf_counter.c
kernel/pid.c
kernel/resource.c
kernel/sysctl.c
kernel/taskstats.c
kernel/time/timer_stats.c
kernel/timer.c
kernel/trace/ftrace.c
kernel/trace/ring_buffer.c
kernel/trace/trace.c
kernel/trace/trace.h
kernel/trace/trace_events.c
kernel/trace/trace_functions.c
kernel/trace/trace_printk.c
kernel/trace/trace_stat.c
lib/Kconfig.debug
mm/dmapool.c
mm/kmemleak.c
mm/memory.c
mm/nommu.c
mm/page-writeback.c
mm/page_alloc.c
mm/percpu.c
net/8021q/vlan.c
net/Kconfig
net/Makefile
net/atm/br2684.c
net/atm/clip.c
net/atm/lec.c
net/atm/mpc.c
net/bluetooth/bnep/netdev.c
net/bridge/br_device.c
net/bridge/br_netfilter.c
net/compat.c
net/core/dev.c
net/core/neighbour.c
net/core/net_namespace.c
net/core/netpoll.c
net/core/rtnetlink.c
net/decnet/dn_route.c
net/econet/af_econet.c
net/ipv4/af_inet.c
net/ipv4/fib_trie.c
net/ipv4/ip_gre.c
net/ipv4/ipip.c
net/ipv4/ipmr.c
net/ipv4/tcp_output.c
net/ipv4/udp.c
net/ipv6/af_inet6.c
net/ipv6/ip6_input.c
net/ipv6/ip6_output.c
net/ipv6/ip6_tunnel.c
net/ipv6/ip6mr.c
net/ipv6/mcast.c
net/ipv6/sit.c
net/ipv6/udp.c
net/irda/irlan/irlan_eth.c
net/irda/irnetlink.c
net/lapb/lapb_iface.c
net/mac80211/Kconfig
net/mac80211/cfg.c
net/mac80211/debugfs_netdev.c
net/mac80211/debugfs_sta.c
net/mac80211/event.c
net/mac80211/ibss.c
net/mac80211/ieee80211_i.h
net/mac80211/iface.c
net/mac80211/key.c
net/mac80211/main.c
net/mac80211/mesh.c
net/mac80211/mesh.h
net/mac80211/mlme.c
net/mac80211/rx.c
net/mac80211/scan.c
net/mac80211/sta_info.h
net/mac80211/tx.c
net/mac80211/wep.c
net/mac80211/wep.h
net/mac80211/wext.c
net/mac80211/wpa.c
net/netfilter/ipvs/ip_vs_ctl.c
net/netlink/af_netlink.c
net/netlink/genetlink.c
net/netrom/nr_dev.c
net/packet/af_packet.c
net/phonet/datagram.c
net/phonet/pep-gprs.c
net/phonet/pep.c
net/phonet/pn_dev.c
net/phonet/socket.c
net/rds/connection.c
net/rds/ib.c
net/rds/ib.h
net/rds/ib_cm.c
net/rds/ib_rdma.c
net/rds/ib_recv.c
net/rds/ib_sysctl.c
net/rds/iw.c
net/rds/iw.h
net/rds/iw_rdma.c
net/rds/iw_send.c
net/rds/rdma_transport.c
net/rds/recv.c
net/rfkill/core.c
net/rose/rose_dev.c
net/sched/sch_teql.c
net/tipc/netlink.c
net/tipc/socket.c
net/wireless/Kconfig
net/wireless/Makefile
net/wireless/core.c
net/wireless/core.h
net/wireless/debugfs.c
net/wireless/debugfs.h
net/wireless/ibss.c
net/wireless/mlme.c
net/wireless/nl80211.c
net/wireless/nl80211.h
net/wireless/reg.c
net/wireless/scan.c
net/wireless/sme.c [new file with mode: 0644]
net/wireless/util.c
net/wireless/wext-compat.c
net/wireless/wext-sme.c [new file with mode: 0644]
net/wireless/wext.c
scripts/.gitignore
scripts/dtc/.gitignore [new file with mode: 0644]
scripts/kernel-doc
scripts/package/builddeb
scripts/pnmtologo.c
security/integrity/ima/ima_main.c
security/integrity/ima/ima_queue.c
sound/isa/cmi8330.c
sound/oss/kahlua.c
sound/oss/mpu401.c
sound/pci/atiixp.c
sound/pci/atiixp_modem.c
sound/pci/au88x0/au8810.c
sound/pci/au88x0/au8820.c
sound/pci/au88x0/au8830.c
sound/pci/ca0106/ca0106_main.c
sound/pci/cmipci.c
sound/pci/cs4281.c
sound/pci/cs46xx/cs46xx.c
sound/pci/emu10k1/emu10k1.c
sound/pci/emu10k1/emu10k1x.c
sound/pci/ens1370.c
sound/pci/es1938.c
sound/pci/hda/hda_codec.c
sound/pci/hda/hda_intel.c
sound/pci/hda/patch_analog.c
sound/pci/hda/patch_ca0110.c
sound/pci/hda/patch_realtek.c
sound/pci/ice1712/ice1712.c
sound/pci/ice1712/ice1724.c
sound/pci/intel8x0.c
sound/pci/intel8x0m.c
sound/pci/lx6464es/lx6464es.c
sound/pci/mixart/mixart.c
sound/pci/nm256/nm256.c
sound/pci/oxygen/oxygen_mixer.c
sound/pci/oxygen/virtuoso.c
sound/pci/rme32.c
sound/pci/rme96.c
sound/pci/sonicvibes.c
sound/pci/via82xx.c
sound/pci/via82xx_modem.c
sound/pci/ymfpci/ymfpci.c
sound/soc/fsl/Kconfig
sound/soc/omap/omap-pcm.c
sound/soc/pxa/pxa2xx-i2s.c
sound/sound_core.c
sound/usb/caiaq/device.c
sound/usb/usx2y/us122l.c
sound/usb/usx2y/usbusx2y.c
tools/perf/CREDITS [new file with mode: 0644]
tools/perf/Documentation/perf-report.txt
tools/perf/Documentation/perf-stat.txt
tools/perf/Makefile
tools/perf/builtin-annotate.c
tools/perf/builtin-record.c
tools/perf/builtin-report.c
tools/perf/builtin-stat.c
tools/perf/builtin-top.c
tools/perf/perf.h
tools/perf/util/callchain.c [new file with mode: 0644]
tools/perf/util/callchain.h [new file with mode: 0644]
tools/perf/util/header.c [new file with mode: 0644]
tools/perf/util/header.h [new file with mode: 0644]
tools/perf/util/help.c
tools/perf/util/pager.c
tools/perf/util/parse-events.c
tools/perf/util/run-command.c
tools/perf/util/run-command.h
tools/perf/util/strbuf.c
tools/perf/util/string.h
tools/perf/util/strlist.c [new file with mode: 0644]
tools/perf/util/strlist.h [new file with mode: 0644]
tools/perf/util/symbol.c
tools/perf/util/symbol.h
tools/perf/util/types.h [moved from tools/perf/types.h with 100% similarity]
tools/perf/util/util.h
virt/kvm/kvm_main.c

index cecb3b0..b93fb7e 100644 (file)
@@ -27,6 +27,7 @@
 *.gz
 *.lzma
 *.patch
+*.gcno
 
 #
 # Top-level generic files
index e8ca040..2d735b0 100644 (file)
@@ -50,7 +50,7 @@ encouraged them to allow separation of the data and integrity metadata
 scatter-gather lists.
 
 The controller will interleave the buffers on write and split them on
-read.  This means that the Linux can DMA the data buffers to and from
+read.  This means that Linux can DMA the data buffers to and from
 host memory without changes to the page cache.
 
 Also, the 16-bit CRC checksum mandated by both the SCSI and SATA specs
@@ -66,7 +66,7 @@ software RAID5).
 
 The IP checksum is weaker than the CRC in terms of detecting bit
 errors.  However, the strength is really in the separation of the data
-buffers and the integrity metadata.  These two distinct buffers much
+buffers and the integrity metadata.  These two distinct buffers must
 match up for an I/O to complete.
 
 The separation of the data and integrity metadata buffers as well as
index f9ca389..1d7e978 100644 (file)
@@ -777,6 +777,18 @@ in cpuset directories:
 # /bin/echo 1-4 > cpus         -> set cpus list to cpus 1,2,3,4
 # /bin/echo 1,2,3,4 > cpus     -> set cpus list to cpus 1,2,3,4
 
+To add a CPU to a cpuset, write the new list of CPUs including the
+CPU to be added. To add 6 to the above cpuset:
+
+# /bin/echo 1-4,6 > cpus       -> set cpus list to cpus 1,2,3,4,6
+
+Similarly to remove a CPU from a cpuset, write the new list of CPUs
+without the CPU to be removed.
+
+To remove all the CPUs:
+
+# /bin/echo "" > cpus          -> clear cpus list
+
 2.3 Setting flags
 -----------------
 
index 8df1a72..d98e4df 100644 (file)
@@ -9,3 +9,8 @@ hostprogs-y := ucon
 always := $(hostprogs-y)
 
 HOSTCFLAGS_ucon.o += -I$(objtree)/usr/include
+
+all: modules
+
+modules clean:
+       $(MAKE) -C ../.. SUBDIRS=$(PWD) $@
index 6a5be5d..1711adc 100644 (file)
@@ -19,6 +19,8 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
+#define pr_fmt(fmt) "cn_test: " fmt
+
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 
 #include <linux/connector.h>
 
-static struct cb_id cn_test_id = { 0x123, 0x456 };
+static struct cb_id cn_test_id = { CN_NETLINK_USERS + 3, 0x456 };
 static char cn_test_name[] = "cn_test";
 static struct sock *nls;
 static struct timer_list cn_test_timer;
 
-void cn_test_callback(void *data)
+static void cn_test_callback(struct cn_msg *msg)
 {
-       struct cn_msg *msg = (struct cn_msg *)data;
-
-       printk("%s: %lu: idx=%x, val=%x, seq=%u, ack=%u, len=%d: %s.\n",
-              __func__, jiffies, msg->id.idx, msg->id.val,
-              msg->seq, msg->ack, msg->len, (char *)msg->data);
+       pr_info("%s: %lu: idx=%x, val=%x, seq=%u, ack=%u, len=%d: %s.\n",
+               __func__, jiffies, msg->id.idx, msg->id.val,
+               msg->seq, msg->ack, msg->len,
+               msg->len ? (char *)msg->data : "");
 }
 
 /*
@@ -63,9 +64,7 @@ static int cn_test_want_notify(void)
 
        skb = alloc_skb(size, GFP_ATOMIC);
        if (!skb) {
-               printk(KERN_ERR "Failed to allocate new skb with size=%u.\n",
-                      size);
-
+               pr_err("failed to allocate new skb with size=%u\n", size);
                return -ENOMEM;
        }
 
@@ -114,12 +113,12 @@ static int cn_test_want_notify(void)
        //netlink_broadcast(nls, skb, 0, ctl->group, GFP_ATOMIC);
        netlink_unicast(nls, skb, 0, 0);
 
-       printk(KERN_INFO "Request was sent. Group=0x%x.\n", ctl->group);
+       pr_info("request was sent: group=0x%x\n", ctl->group);
 
        return 0;
 
 nlmsg_failure:
-       printk(KERN_ERR "Failed to send %u.%u\n", msg->seq, msg->ack);
+       pr_err("failed to send %u.%u\n", msg->seq, msg->ack);
        kfree_skb(skb);
        return -EINVAL;
 }
@@ -131,6 +130,8 @@ static void cn_test_timer_func(unsigned long __data)
        struct cn_msg *m;
        char data[32];
 
+       pr_debug("%s: timer fired with data %lu\n", __func__, __data);
+
        m = kzalloc(sizeof(*m) + sizeof(data), GFP_ATOMIC);
        if (m) {
 
@@ -150,7 +151,7 @@ static void cn_test_timer_func(unsigned long __data)
 
        cn_test_timer_counter++;
 
-       mod_timer(&cn_test_timer, jiffies + HZ);
+       mod_timer(&cn_test_timer, jiffies + msecs_to_jiffies(1000));
 }
 
 static int cn_test_init(void)
@@ -168,8 +169,10 @@ static int cn_test_init(void)
        }
 
        setup_timer(&cn_test_timer, cn_test_timer_func, 0);
-       cn_test_timer.expires = jiffies + HZ;
-       add_timer(&cn_test_timer);
+       mod_timer(&cn_test_timer, jiffies + msecs_to_jiffies(1000));
+
+       pr_info("initialized with id={%u.%u}\n",
+               cn_test_id.idx, cn_test_id.val);
 
        return 0;
 
index ad6e0ba..81e6bf6 100644 (file)
@@ -5,10 +5,10 @@ Kernel Connector.
 Kernel connector - new netlink based userspace <-> kernel space easy
 to use communication module.
 
-Connector driver adds possibility to connect various agents using
-netlink based network.  One must register callback and
-identifier. When driver receives special netlink message with
-appropriate identifier, appropriate callback will be called.
+The Connector driver makes it easy to connect various agents using a
+netlink based network.  One must register a callback and an identifier.
+When the driver receives a special netlink message with the appropriate
+identifier, the appropriate callback will be called.
 
 From the userspace point of view it's quite straightforward:
 
@@ -17,10 +17,10 @@ From the userspace point of view it's quite straightforward:
        send();
        recv();
 
-But if kernelspace want to use full power of such connections, driver
-writer must create special sockets, must know about struct sk_buff
-handling...  Connector allows any kernelspace agents to use netlink
-based networking for inter-process communication in a significantly
+But if kernelspace wants to use the full power of such connections, the
+driver writer must create special sockets, must know about struct sk_buff
+handling, etc...  The Connector driver allows any kernelspace agents to use
+netlink based networking for inter-process communication in a significantly
 easier way:
 
 int cn_add_callback(struct cb_id *id, char *name, void (*callback) (void *));
@@ -32,15 +32,15 @@ struct cb_id
        __u32                   val;
 };
 
-idx and val are unique identifiers which must be registered in
-connector.h for in-kernel usage.  void (*callback) (void *) - is a
-callback function which will be called when message with above idx.val
-will be received by connector core.  Argument for that function must
+idx and val are unique identifiers which must be registered in the
+connector.h header for in-kernel usage.  void (*callback) (void *) is a
+callback function which will be called when message with above idx.val
+is received by the connector core.  The argument for that function must
 be dereferenced to struct cn_msg *.
 
 struct cn_msg
 {
-       struct cb_id            id;
+       struct cb_id            id;
 
        __u32                   seq;
        __u32                   ack;
@@ -55,92 +55,95 @@ Connector interfaces.
 
 int cn_add_callback(struct cb_id *id, char *name, void (*callback) (void *));
 
-Registers new callback with connector core.
+ Registers new callback with connector core.
 
-struct cb_id *id               - unique connector's user identifier.
-                                 It must be registered in connector.h for legal in-kernel users.
-char *name                     - connector's callback symbolic name.
-void (*callback) (void *)      - connector's callback.
+ struct cb_id *id              - unique connector's user identifier.
+                                 It must be registered in connector.h for legal in-kernel users.
+ char *name                    - connector's callback symbolic name.
+ void (*callback) (void *)     - connector's callback.
                                  Argument must be dereferenced to struct cn_msg *.
 
+
 void cn_del_callback(struct cb_id *id);
 
-Unregisters new callback with connector core.
+ Unregisters new callback with connector core.
+
+ struct cb_id *id              - unique connector's user identifier.
 
-struct cb_id *id               - unique connector's user identifier.
 
 int cn_netlink_send(struct cn_msg *msg, u32 __groups, int gfp_mask);
 
-Sends message to the specified groups.  It can be safely called from
-softirq context, but may silently fail under strong memory pressure.
-If there are no listeners for given group -ESRCH can be returned.
+ Sends message to the specified groups.  It can be safely called from
+ softirq context, but may silently fail under strong memory pressure.
+ If there are no listeners for given group -ESRCH can be returned.
 
-struct cn_msg *                        - message header(with attached data).
-u32 __group                    - destination group.
+ struct cn_msg *               - message header(with attached data).
+ u32 __group                   - destination group.
                                  If __group is zero, then appropriate group will
                                  be searched through all registered connector users,
                                  and message will be delivered to the group which was
                                  created for user with the same ID as in msg.
                                  If __group is not zero, then message will be delivered
                                  to the specified group.
-int gfp_mask                   - GFP mask.
+ int gfp_mask                  - GFP mask.
 
-Note: When registering new callback user, connector core assigns
-netlink group to the user which is equal to it's id.idx.
+ Note: When registering new callback user, connector core assigns
+ netlink group to the user which is equal to it's id.idx.
 
 /*****************************************/
 Protocol description.
 /*****************************************/
 
-Current offers transport layer with fixed header.  Recommended
-protocol which uses such header is following:
+The current framework offers a transport layer with fixed headers.  The
+recommended protocol which uses such a header is as following:
 
 msg->seq and msg->ack are used to determine message genealogy.  When
-someone sends message it puts there locally unique sequence and random
-acknowledge numbers.  Sequence number may be copied into
+someone sends a message, they use a locally unique sequence and random
+acknowledge number.  The sequence number may be copied into
 nlmsghdr->nlmsg_seq too.
 
-Sequence number is incremented with each message to be sent.
+The sequence number is incremented with each message sent.
 
-If we expect reply to our message, then sequence number in received
-message MUST be the same as in original message, and acknowledge
-number MUST be the same + 1.
+If you expect a reply to the message, then the sequence number in the
+received message MUST be the same as in the original message, and the
+acknowledge number MUST be the same + 1.
 
-If we receive message and it's sequence number is not equal to one we
-are expecting, then it is new message.  If we receive message and it's
-sequence number is the same as one we are expecting, but it's
-acknowledge is not equal acknowledge number in original message + 1,
-then it is new message.
+If we receive a message and its sequence number is not equal to one we
+are expecting, then it is a new message.  If we receive a message and
+its sequence number is the same as one we are expecting, but its
+acknowledge is not equal to the acknowledge number in the original
+message + 1, then it is a new message.
 
-Obviously, protocol header contains above id.
+Obviously, the protocol header contains the above id.
 
-connector allows event notification in the following form: kernel
+The connector allows event notification in the following form: kernel
 driver or userspace process can ask connector to notify it when
-selected id's will be turned on or off(registered or unregistered it's
-callback). It is done by sending special command to connector
-driver(it also registers itself with id={-1, -1}).
+selected ids will be turned on or off (registered or unregistered its
+callback).  It is done by sending a special command to the connector
+driver (it also registers itself with id={-1, -1}).
 
-As example of usage Documentation/connector now contains cn_test.c -
-testing module which uses connector to request notification and to
-send messages.
+As example of this usage can be found in the cn_test.c module which
+uses the connector to request notification and to send messages.
 
 /*****************************************/
 Reliability.
 /*****************************************/
 
-Netlink itself is not reliable protocol, that means that messages can
+Netlink itself is not a reliable protocol.  That means that messages can
 be lost due to memory pressure or process' receiving queue overflowed,
-so caller is warned must be prepared. That is why struct cn_msg [main
-connector's message header] contains u32 seq and u32 ack fields.
+so caller is warned that it must be prepared.  That is why the struct
+cn_msg [main connector's message header] contains u32 seq and u32 ack
+fields.
 
 /*****************************************/
 Userspace usage.
 /*****************************************/
+
 2.6.14 has a new netlink socket implementation, which by default does not
-allow to send data to netlink groups other than 1.
-So, if to use netlink socket (for example using connector) 
-with different group number userspace application must subscribe to 
-that group. It can be achieved by following pseudocode:
+allow people to send data to netlink groups other than 1.
+So, if you wish to use a netlink socket (for example using connector)
+with a different group number, the userspace application must subscribe to
+that group first.  It can be achieved by the following pseudocode:
 
 s = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR);
 
@@ -160,8 +163,8 @@ if (bind(s, (struct sockaddr *)&l_local, sizeof(struct sockaddr_nl)) == -1) {
 }
 
 Where 270 above is SOL_NETLINK, and 1 is a NETLINK_ADD_MEMBERSHIP socket
-option. To drop multicast subscription one should call above socket option
-with NETLINK_DROP_MEMBERSHIP parameter which is defined as 0.
+option.  To drop a multicast subscription, one should call the above socket
+option with the NETLINK_DROP_MEMBERSHIP parameter which is defined as 0.
 
 2.6.14 netlink code only allows to select a group which is less or equal to
 the maximum group number, which is used at netlink_kernel_create() time.
index c5092ad..4848db8 100644 (file)
 
 #include <arpa/inet.h>
 
+#include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
 #include <string.h>
 #include <errno.h>
 #include <time.h>
+#include <getopt.h>
 
 #include <linux/connector.h>
 
 #define DEBUG
 #define NETLINK_CONNECTOR      11
 
+/* Hopefully your userspace connector.h matches this kernel */
+#define CN_TEST_IDX            CN_NETLINK_USERS + 3
+#define CN_TEST_VAL            0x456
+
 #ifdef DEBUG
 #define ulog(f, a...) fprintf(stdout, f, ##a)
 #else
@@ -83,6 +89,25 @@ static int netlink_send(int s, struct cn_msg *msg)
        return err;
 }
 
+static void usage(void)
+{
+       printf(
+               "Usage: ucon [options] [output file]\n"
+               "\n"
+               "\t-h\tthis help screen\n"
+               "\t-s\tsend buffers to the test module\n"
+               "\n"
+               "The default behavior of ucon is to subscribe to the test module\n"
+               "and wait for state messages.  Any ones received are dumped to the\n"
+               "specified output file (or stdout).  The test module is assumed to\n"
+               "have an id of {%u.%u}\n"
+               "\n"
+               "If you get no output, then verify the cn_test module id matches\n"
+               "the expected id above.\n"
+               , CN_TEST_IDX, CN_TEST_VAL
+       );
+}
+
 int main(int argc, char *argv[])
 {
        int s;
@@ -94,17 +119,34 @@ int main(int argc, char *argv[])
        FILE *out;
        time_t tm;
        struct pollfd pfd;
+       bool send_msgs = false;
 
-       if (argc < 2)
-               out = stdout;
-       else {
-               out = fopen(argv[1], "a+");
+       while ((s = getopt(argc, argv, "hs")) != -1) {
+               switch (s) {
+               case 's':
+                       send_msgs = true;
+                       break;
+
+               case 'h':
+                       usage();
+                       return 0;
+
+               default:
+                       /* getopt() outputs an error for us */
+                       usage();
+                       return 1;
+               }
+       }
+
+       if (argc != optind) {
+               out = fopen(argv[optind], "a+");
                if (!out) {
                        ulog("Unable to open %s for writing: %s\n",
                                argv[1], strerror(errno));
                        out = stdout;
                }
-       }
+       } else
+               out = stdout;
 
        memset(buf, 0, sizeof(buf));
 
@@ -115,9 +157,11 @@ int main(int argc, char *argv[])
        }
 
        l_local.nl_family = AF_NETLINK;
-       l_local.nl_groups = 0x123; /* bitmask of requested groups */
+       l_local.nl_groups = -1; /* bitmask of requested groups */
        l_local.nl_pid = 0;
 
+       ulog("subscribing to %u.%u\n", CN_TEST_IDX, CN_TEST_VAL);
+
        if (bind(s, (struct sockaddr *)&l_local, sizeof(struct sockaddr_nl)) == -1) {
                perror("bind");
                close(s);
@@ -130,15 +174,15 @@ int main(int argc, char *argv[])
                setsockopt(s, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, &on, sizeof(on));
        }
 #endif
-       if (0) {
+       if (send_msgs) {
                int i, j;
 
                memset(buf, 0, sizeof(buf));
 
                data = (struct cn_msg *)buf;
 
-               data->id.idx = 0x123;
-               data->id.val = 0x456;
+               data->id.idx = CN_TEST_IDX;
+               data->id.val = CN_TEST_VAL;
                data->seq = seq++;
                data->ack = 0;
                data->len = 0;
index e716aad..40ec633 100644 (file)
@@ -188,13 +188,18 @@ Solution: Exclude affected source files from profiling by specifying
           GCOV_PROFILE := n or GCOV_PROFILE_basename.o := n in the
           corresponding Makefile.
 
+Problem:  Files copied from sysfs appear empty or incomplete.
+Cause:    Due to the way seq_file works, some tools such as cp or tar
+          may not correctly copy files from sysfs.
+Solution: Use 'cat' to read .gcda files and 'cp -d' to copy links.
+          Alternatively use the mechanism shown in Appendix B.
+
 
 Appendix A: gather_on_build.sh
 ==============================
 
 Sample script to gather coverage meta files on the build machine
 (see 6a):
-
 #!/bin/bash
 
 KSRC=$1
@@ -226,7 +231,7 @@ Appendix B: gather_on_test.sh
 Sample script to gather coverage data files on the test machine
 (see 6b):
 
-#!/bin/bash
+#!/bin/bash -e
 
 DEST=$1
 GCDA=/sys/kernel/debug/gcov
@@ -236,11 +241,13 @@ if [ -z "$DEST" ] ; then
   exit 1
 fi
 
-find $GCDA -name '*.gcno' -o -name '*.gcda' | tar cfz $DEST -T -
+TEMPDIR=$(mktemp -d)
+echo Collecting data..
+find $GCDA -type d -exec mkdir -p $TEMPDIR/\{\} \;
+find $GCDA -name '*.gcda' -exec sh -c 'cat < $0 > '$TEMPDIR'/$0' {} \;
+find $GCDA -name '*.gcno' -exec sh -c 'cp -d $0 '$TEMPDIR'/$0' {} \;
+tar czf $DEST -C $TEMPDIR sys
+rm -rf $TEMPDIR
 
-if [ $? -eq 0 ] ; then
-  echo "$DEST successfully created, copy to build system and unpack with:"
-  echo "  tar xfz $DEST"
-else
-  echo "Could not create file $DEST"
-fi
+echo "$DEST successfully created, copy to build system and unpack with:"
+echo "  tar xfz $DEST"
index d08759a..9347f4a 100644 (file)
@@ -1531,6 +1531,11 @@ and is between 256 and 4096 characters. It is defined in the file
                        symbolic names: lapic and ioapic
                        Example: nmi_watchdog=2 or nmi_watchdog=panic,lapic
 
+       netpoll.carrier_timeout=
+                       [NET] Specifies amount of time (in seconds) that
+                       netpoll should wait for a carrier. By default netpoll
+                       waits 4 seconds.
+
        no387           [BUGS=X86-32] Tells the kernel to use the 387 maths
                        emulation library even if a 387 maths coprocessor
                        is present.
@@ -1915,6 +1920,12 @@ and is between 256 and 4096 characters. It is defined in the file
                        Format: { 0 | 1 }
                        See arch/parisc/kernel/pdc_chassis.c
 
+       percpu_alloc=   [X86] Select which percpu first chunk allocator to use.
+                       Allowed values are one of "lpage", "embed" and "4k".
+                       See comments in arch/x86/kernel/setup_percpu.c for
+                       details on each allocator.  This parameter is primarily
+                       for debugging and performance comparison.
+
        pf.             [PARIDE]
                        See Documentation/blockdev/paride.txt.
 
@@ -2467,7 +2478,8 @@ and is between 256 and 4096 characters. It is defined in the file
 
        tp720=          [HW,PS2]
 
-       trace_buf_size=nn[KMG] [ftrace] will set tracing buffer size.
+       trace_buf_size=nn[KMG]
+                       [FTRACE] will set tracing buffer size.
 
        trix=           [HW,OSS] MediaTrix AudioTrix Pro
                        Format:
index 0112da3..8906803 100644 (file)
@@ -16,13 +16,17 @@ Usage
 -----
 
 CONFIG_DEBUG_KMEMLEAK in "Kernel hacking" has to be enabled. A kernel
-thread scans the memory every 10 minutes (by default) and prints any new
-unreferenced objects found. To trigger an intermediate scan and display
-all the possible memory leaks:
+thread scans the memory every 10 minutes (by default) and prints the
+number of new unreferenced objects found. To display the details of all
+the possible memory leaks:
 
   # mount -t debugfs nodev /sys/kernel/debug/
   # cat /sys/kernel/debug/kmemleak
 
+To trigger an intermediate memory scan:
+
+  # echo scan > /sys/kernel/debug/kmemleak
+
 Note that the orphan objects are listed in the order they were allocated
 and one object at the beginning of the list may cause other subsequent
 objects to be reported as orphan.
@@ -31,16 +35,21 @@ Memory scanning parameters can be modified at run-time by writing to the
 /sys/kernel/debug/kmemleak file. The following parameters are supported:
 
   off          - disable kmemleak (irreversible)
-  stack=on     - enable the task stacks scanning
+  stack=on     - enable the task stacks scanning (default)
   stack=off    - disable the tasks stacks scanning
-  scan=on      - start the automatic memory scanning thread
+  scan=on      - start the automatic memory scanning thread (default)
   scan=off     - stop the automatic memory scanning thread
-  scan=<secs>  - set the automatic memory scanning period in seconds (0
-                 to disable it)
+  scan=<secs>  - set the automatic memory scanning period in seconds
+                 (default 600, 0 to stop the automatic scanning)
+  scan         - trigger a memory scan
 
 Kmemleak can also be disabled at boot-time by passing "kmemleak=off" on
 the kernel command line.
 
+Memory may be allocated or freed before kmemleak is initialised and
+these actions are stored in an early log buffer. The size of this buffer
+is configured via the CONFIG_DEBUG_KMEMLEAK_EARLY_LOG_SIZE option.
+
 Basic Algorithm
 ---------------
 
diff --git a/Documentation/leds-lp3944.txt b/Documentation/leds-lp3944.txt
new file mode 100644 (file)
index 0000000..c6eda18
--- /dev/null
@@ -0,0 +1,50 @@
+Kernel driver lp3944
+====================
+
+  * National Semiconductor LP3944 Fun-light Chip
+    Prefix: 'lp3944'
+    Addresses scanned: None (see the Notes section below)
+    Datasheet: Publicly available at the National Semiconductor website
+               http://www.national.com/pf/LP/LP3944.html
+
+Authors:
+        Antonio Ospite <ospite@studenti.unina.it>
+
+
+Description
+-----------
+The LP3944 is a helper chip that can drive up to 8 leds, with two programmable
+DIM modes; it could even be used as a gpio expander but this driver assumes it
+is used as a led controller.
+
+The DIM modes are used to set _blink_ patterns for leds, the pattern is
+specified supplying two parameters:
+  - period: from 0s to 1.6s
+  - duty cycle: percentage of the period the led is on, from 0 to 100
+
+Setting a led in DIM0 or DIM1 mode makes it blink according to the pattern.
+See the datasheet for details.
+
+LP3944 can be found on Motorola A910 smartphone, where it drives the rgb
+leds, the camera flash light and the lcds power.
+
+
+Notes
+-----
+The chip is used mainly in embedded contexts, so this driver expects it is
+registered using the i2c_board_info mechanism.
+
+To register the chip at address 0x60 on adapter 0, set the platform data
+according to include/linux/leds-lp3944.h, set the i2c board info:
+
+       static struct i2c_board_info __initdata a910_i2c_board_info[] = {
+               {
+                       I2C_BOARD_INFO("lp3944", 0x60),
+                       .platform_data = &a910_lp3944_leds,
+               },
+       };
+
+and register it in the platform init function
+
+       i2c_register_board_info(0, a910_i2c_board_info,
+                       ARRAY_SIZE(a910_i2c_board_info));
index 8d999d8..79f533f 100644 (file)
@@ -1238,1122 +1238,7 @@ descriptions for the SOC devices for which new nodes have been
 defined; this list will expand as more and more SOC-containing
 platforms are moved over to use the flattened-device-tree model.
 
-   a) PHY nodes
-
-   Required properties:
-
-    - device_type : Should be "ethernet-phy"
-    - interrupts : <a b> where a is the interrupt number and b is a
-      field that represents an encoding of the sense and level
-      information for the interrupt.  This should be encoded based on
-      the information in section 2) depending on the type of interrupt
-      controller you have.
-    - interrupt-parent : the phandle for the interrupt controller that
-      services interrupts for this device.
-    - reg : The ID number for the phy, usually a small integer
-    - linux,phandle :  phandle for this node; likely referenced by an
-      ethernet controller node.
-
-
-   Example:
-
-       ethernet-phy@0 {
-               linux,phandle = <2452000>
-               interrupt-parent = <40000>;
-               interrupts = <35 1>;
-               reg = <0>;
-               device_type = "ethernet-phy";
-       };
-
-
-   b) Interrupt controllers
-
-   Some SOC devices contain interrupt controllers that are different
-   from the standard Open PIC specification.  The SOC device nodes for
-   these types of controllers should be specified just like a standard
-   OpenPIC controller.  Sense and level information should be encoded
-   as specified in section 2) of this chapter for each device that
-   specifies an interrupt.
-
-   Example :
-
-       pic@40000 {
-               linux,phandle = <40000>;
-               interrupt-controller;
-               #address-cells = <0>;
-               reg = <40000 40000>;
-               compatible = "chrp,open-pic";
-               device_type = "open-pic";
-       };
-
-    c) 4xx/Axon EMAC ethernet nodes
-
-    The EMAC ethernet controller in IBM and AMCC 4xx chips, and also
-    the Axon bridge.  To operate this needs to interact with a ths
-    special McMAL DMA controller, and sometimes an RGMII or ZMII
-    interface.  In addition to the nodes and properties described
-    below, the node for the OPB bus on which the EMAC sits must have a
-    correct clock-frequency property.
-
-      i) The EMAC node itself
-
-    Required properties:
-    - device_type       : "network"
-
-    - compatible        : compatible list, contains 2 entries, first is
-                         "ibm,emac-CHIP" where CHIP is the host ASIC (440gx,
-                         405gp, Axon) and second is either "ibm,emac" or
-                         "ibm,emac4".  For Axon, thus, we have: "ibm,emac-axon",
-                         "ibm,emac4"
-    - interrupts        : <interrupt mapping for EMAC IRQ and WOL IRQ>
-    - interrupt-parent  : optional, if needed for interrupt mapping
-    - reg               : <registers mapping>
-    - local-mac-address : 6 bytes, MAC address
-    - mal-device        : phandle of the associated McMAL node
-    - mal-tx-channel    : 1 cell, index of the tx channel on McMAL associated
-                         with this EMAC
-    - mal-rx-channel    : 1 cell, index of the rx channel on McMAL associated
-                         with this EMAC
-    - cell-index        : 1 cell, hardware index of the EMAC cell on a given
-                         ASIC (typically 0x0 and 0x1 for EMAC0 and EMAC1 on
-                         each Axon chip)
-    - max-frame-size    : 1 cell, maximum frame size supported in bytes
-    - rx-fifo-size      : 1 cell, Rx fifo size in bytes for 10 and 100 Mb/sec
-                         operations.
-                         For Axon, 2048
-    - tx-fifo-size      : 1 cell, Tx fifo size in bytes for 10 and 100 Mb/sec
-                         operations.
-                         For Axon, 2048.
-    - fifo-entry-size   : 1 cell, size of a fifo entry (used to calculate
-                         thresholds).
-                         For Axon, 0x00000010
-    - mal-burst-size    : 1 cell, MAL burst size (used to calculate thresholds)
-                         in bytes.
-                         For Axon, 0x00000100 (I think ...)
-    - phy-mode          : string, mode of operations of the PHY interface.
-                         Supported values are: "mii", "rmii", "smii", "rgmii",
-                         "tbi", "gmii", rtbi", "sgmii".
-                         For Axon on CAB, it is "rgmii"
-    - mdio-device       : 1 cell, required iff using shared MDIO registers
-                         (440EP).  phandle of the EMAC to use to drive the
-                         MDIO lines for the PHY used by this EMAC.
-    - zmii-device       : 1 cell, required iff connected to a ZMII.  phandle of
-                         the ZMII device node
-    - zmii-channel      : 1 cell, required iff connected to a ZMII.  Which ZMII
-                         channel or 0xffffffff if ZMII is only used for MDIO.
-    - rgmii-device      : 1 cell, required iff connected to an RGMII. phandle
-                         of the RGMII device node.
-                         For Axon: phandle of plb5/plb4/opb/rgmii
-    - rgmii-channel     : 1 cell, required iff connected to an RGMII.  Which
-                         RGMII channel is used by this EMAC.
-                         Fox Axon: present, whatever value is appropriate for each
-                         EMAC, that is the content of the current (bogus) "phy-port"
-                         property.
-
-    Optional properties:
-    - phy-address       : 1 cell, optional, MDIO address of the PHY. If absent,
-                         a search is performed.
-    - phy-map           : 1 cell, optional, bitmap of addresses to probe the PHY
-                         for, used if phy-address is absent. bit 0x00000001 is
-                         MDIO address 0.
-                         For Axon it can be absent, though my current driver
-                         doesn't handle phy-address yet so for now, keep
-                         0x00ffffff in it.
-    - rx-fifo-size-gige : 1 cell, Rx fifo size in bytes for 1000 Mb/sec
-                         operations (if absent the value is the same as
-                         rx-fifo-size).  For Axon, either absent or 2048.
-    - tx-fifo-size-gige : 1 cell, Tx fifo size in bytes for 1000 Mb/sec
-                         operations (if absent the value is the same as
-                         tx-fifo-size). For Axon, either absent or 2048.
-    - tah-device        : 1 cell, optional. If connected to a TAH engine for
-                         offload, phandle of the TAH device node.
-    - tah-channel       : 1 cell, optional. If appropriate, channel used on the
-                         TAH engine.
-
-    Example:
-
-       EMAC0: ethernet@40000800 {
-               device_type = "network";
-               compatible = "ibm,emac-440gp", "ibm,emac";
-               interrupt-parent = <&UIC1>;
-               interrupts = <1c 4 1d 4>;
-               reg = <40000800 70>;
-               local-mac-address = [00 04 AC E3 1B 1E];
-               mal-device = <&MAL0>;
-               mal-tx-channel = <0 1>;
-               mal-rx-channel = <0>;
-               cell-index = <0>;
-               max-frame-size = <5dc>;
-               rx-fifo-size = <1000>;
-               tx-fifo-size = <800>;
-               phy-mode = "rmii";
-               phy-map = <00000001>;
-               zmii-device = <&ZMII0>;
-               zmii-channel = <0>;
-       };
-
-      ii) McMAL node
-
-    Required properties:
-    - device_type        : "dma-controller"
-    - compatible         : compatible list, containing 2 entries, first is
-                          "ibm,mcmal-CHIP" where CHIP is the host ASIC (like
-                          emac) and the second is either "ibm,mcmal" or
-                          "ibm,mcmal2".
-                          For Axon, "ibm,mcmal-axon","ibm,mcmal2"
-    - interrupts         : <interrupt mapping for the MAL interrupts sources:
-                           5 sources: tx_eob, rx_eob, serr, txde, rxde>.
-                           For Axon: This is _different_ from the current
-                          firmware.  We use the "delayed" interrupts for txeob
-                          and rxeob. Thus we end up with mapping those 5 MPIC
-                          interrupts, all level positive sensitive: 10, 11, 32,
-                          33, 34 (in decimal)
-    - dcr-reg            : < DCR registers range >
-    - dcr-parent         : if needed for dcr-reg
-    - num-tx-chans       : 1 cell, number of Tx channels
-    - num-rx-chans       : 1 cell, number of Rx channels
-
-      iii) ZMII node
-
-    Required properties:
-    - compatible         : compatible list, containing 2 entries, first is
-                          "ibm,zmii-CHIP" where CHIP is the host ASIC (like
-                          EMAC) and the second is "ibm,zmii".
-                          For Axon, there is no ZMII node.
-    - reg                : <registers mapping>
-
-      iv) RGMII node
-
-    Required properties:
-    - compatible         : compatible list, containing 2 entries, first is
-                          "ibm,rgmii-CHIP" where CHIP is the host ASIC (like
-                          EMAC) and the second is "ibm,rgmii".
-                           For Axon, "ibm,rgmii-axon","ibm,rgmii"
-    - reg                : <registers mapping>
-    - revision           : as provided by the RGMII new version register if
-                          available.
-                          For Axon: 0x0000012a
-
-   d) Xilinx IP cores
-
-   The Xilinx EDK toolchain ships with a set of IP cores (devices) for use
-   in Xilinx Spartan and Virtex FPGAs.  The devices cover the whole range
-   of standard device types (network, serial, etc.) and miscellaneous
-   devices (gpio, LCD, spi, etc).  Also, since these devices are
-   implemented within the fpga fabric every instance of the device can be
-   synthesised with different options that change the behaviour.
-
-   Each IP-core has a set of parameters which the FPGA designer can use to
-   control how the core is synthesized.  Historically, the EDK tool would
-   extract the device parameters relevant to device drivers and copy them
-   into an 'xparameters.h' in the form of #define symbols.  This tells the
-   device drivers how the IP cores are configured, but it requres the kernel
-   to be recompiled every time the FPGA bitstream is resynthesized.
-
-   The new approach is to export the parameters into the device tree and
-   generate a new device tree each time the FPGA bitstream changes.  The
-   parameters which used to be exported as #defines will now become
-   properties of the device node.  In general, device nodes for IP-cores
-   will take the following form:
-
-       (name): (generic-name)@(base-address) {
-               compatible = "xlnx,(ip-core-name)-(HW_VER)"
-                            [, (list of compatible devices), ...];
-               reg = <(baseaddr) (size)>;
-               interrupt-parent = <&interrupt-controller-phandle>;
-               interrupts = < ... >;
-               xlnx,(parameter1) = "(string-value)";
-               xlnx,(parameter2) = <(int-value)>;
-       };
-
-       (generic-name):   an open firmware-style name that describes the
-                       generic class of device.  Preferably, this is one word, such
-                       as 'serial' or 'ethernet'.
-       (ip-core-name): the name of the ip block (given after the BEGIN
-                       directive in system.mhs).  Should be in lowercase
-                       and all underscores '_' converted to dashes '-'.
-       (name):         is derived from the "PARAMETER INSTANCE" value.
-       (parameter#):   C_* parameters from system.mhs.  The C_ prefix is
-                       dropped from the parameter name, the name is converted
-                       to lowercase and all underscore '_' characters are
-                       converted to dashes '-'.
-       (baseaddr):     the baseaddr parameter value (often named C_BASEADDR).
-       (HW_VER):       from the HW_VER parameter.
-       (size):         the address range size (often C_HIGHADDR - C_BASEADDR + 1).
-
-   Typically, the compatible list will include the exact IP core version
-   followed by an older IP core version which implements the same
-   interface or any other device with the same interface.
-
-   'reg', 'interrupt-parent' and 'interrupts' are all optional properties.
-
-   For example, the following block from system.mhs:
-
-       BEGIN opb_uartlite
-               PARAMETER INSTANCE = opb_uartlite_0
-               PARAMETER HW_VER = 1.00.b
-               PARAMETER C_BAUDRATE = 115200
-               PARAMETER C_DATA_BITS = 8
-               PARAMETER C_ODD_PARITY = 0
-               PARAMETER C_USE_PARITY = 0
-               PARAMETER C_CLK_FREQ = 50000000
-               PARAMETER C_BASEADDR = 0xEC100000
-               PARAMETER C_HIGHADDR = 0xEC10FFFF
-               BUS_INTERFACE SOPB = opb_7
-               PORT OPB_Clk = CLK_50MHz
-               PORT Interrupt = opb_uartlite_0_Interrupt
-               PORT RX = opb_uartlite_0_RX
-               PORT TX = opb_uartlite_0_TX
-               PORT OPB_Rst = sys_bus_reset_0
-       END
-
-   becomes the following device tree node:
-
-       opb_uartlite_0: serial@ec100000 {
-               device_type = "serial";
-               compatible = "xlnx,opb-uartlite-1.00.b";
-               reg = <ec100000 10000>;
-               interrupt-parent = <&opb_intc_0>;
-               interrupts = <1 0>; // got this from the opb_intc parameters
-               current-speed = <d#115200>;     // standard serial device prop
-               clock-frequency = <d#50000000>; // standard serial device prop
-               xlnx,data-bits = <8>;
-               xlnx,odd-parity = <0>;
-               xlnx,use-parity = <0>;
-       };
-
-   Some IP cores actually implement 2 or more logical devices.  In
-   this case, the device should still describe the whole IP core with
-   a single node and add a child node for each logical device.  The
-   ranges property can be used to translate from parent IP-core to the
-   registers of each device.  In addition, the parent node should be
-   compatible with the bus type 'xlnx,compound', and should contain
-   #address-cells and #size-cells, as with any other bus.  (Note: this
-   makes the assumption that both logical devices have the same bus
-   binding.  If this is not true, then separate nodes should be used
-   for each logical device).  The 'cell-index' property can be used to
-   enumerate logical devices within an IP core.  For example, the
-   following is the system.mhs entry for the dual ps2 controller found
-   on the ml403 reference design.
-
-       BEGIN opb_ps2_dual_ref
-               PARAMETER INSTANCE = opb_ps2_dual_ref_0
-               PARAMETER HW_VER = 1.00.a
-               PARAMETER C_BASEADDR = 0xA9000000
-               PARAMETER C_HIGHADDR = 0xA9001FFF
-               BUS_INTERFACE SOPB = opb_v20_0
-               PORT Sys_Intr1 = ps2_1_intr
-               PORT Sys_Intr2 = ps2_2_intr
-               PORT Clkin1 = ps2_clk_rx_1
-               PORT Clkin2 = ps2_clk_rx_2
-               PORT Clkpd1 = ps2_clk_tx_1
-               PORT Clkpd2 = ps2_clk_tx_2
-               PORT Rx1 = ps2_d_rx_1
-               PORT Rx2 = ps2_d_rx_2
-               PORT Txpd1 = ps2_d_tx_1
-               PORT Txpd2 = ps2_d_tx_2
-       END
-
-   It would result in the following device tree nodes:
-
-       opb_ps2_dual_ref_0: opb-ps2-dual-ref@a9000000 {
-               #address-cells = <1>;
-               #size-cells = <1>;
-               compatible = "xlnx,compound";
-               ranges = <0 a9000000 2000>;
-               // If this device had extra parameters, then they would
-               // go here.
-               ps2@0 {
-                       compatible = "xlnx,opb-ps2-dual-ref-1.00.a";
-                       reg = <0 40>;
-                       interrupt-parent = <&opb_intc_0>;
-                       interrupts = <3 0>;
-                       cell-index = <0>;
-               };
-               ps2@1000 {
-                       compatible = "xlnx,opb-ps2-dual-ref-1.00.a";
-                       reg = <1000 40>;
-                       interrupt-parent = <&opb_intc_0>;
-                       interrupts = <3 0>;
-                       cell-index = <0>;
-               };
-       };
-
-   Also, the system.mhs file defines bus attachments from the processor
-   to the devices.  The device tree structure should reflect the bus
-   attachments.  Again an example; this system.mhs fragment:
-
-       BEGIN ppc405_virtex4
-               PARAMETER INSTANCE = ppc405_0
-               PARAMETER HW_VER = 1.01.a
-               BUS_INTERFACE DPLB = plb_v34_0
-               BUS_INTERFACE IPLB = plb_v34_0
-       END
-
-       BEGIN opb_intc
-               PARAMETER INSTANCE = opb_intc_0
-               PARAMETER HW_VER = 1.00.c
-               PARAMETER C_BASEADDR = 0xD1000FC0
-               PARAMETER C_HIGHADDR = 0xD1000FDF
-               BUS_INTERFACE SOPB = opb_v20_0
-       END
-
-       BEGIN opb_uart16550
-               PARAMETER INSTANCE = opb_uart16550_0
-               PARAMETER HW_VER = 1.00.d
-               PARAMETER C_BASEADDR = 0xa0000000
-               PARAMETER C_HIGHADDR = 0xa0001FFF
-               BUS_INTERFACE SOPB = opb_v20_0
-       END
-
-       BEGIN plb_v34
-               PARAMETER INSTANCE = plb_v34_0
-               PARAMETER HW_VER = 1.02.a
-       END
-
-       BEGIN plb_bram_if_cntlr
-               PARAMETER INSTANCE = plb_bram_if_cntlr_0
-               PARAMETER HW_VER = 1.00.b
-               PARAMETER C_BASEADDR = 0xFFFF0000
-               PARAMETER C_HIGHADDR = 0xFFFFFFFF
-               BUS_INTERFACE SPLB = plb_v34_0
-       END
-
-       BEGIN plb2opb_bridge
-               PARAMETER INSTANCE = plb2opb_bridge_0
-               PARAMETER HW_VER = 1.01.a
-               PARAMETER C_RNG0_BASEADDR = 0x20000000
-               PARAMETER C_RNG0_HIGHADDR = 0x3FFFFFFF
-               PARAMETER C_RNG1_BASEADDR = 0x60000000
-               PARAMETER C_RNG1_HIGHADDR = 0x7FFFFFFF
-               PARAMETER C_RNG2_BASEADDR = 0x80000000
-               PARAMETER C_RNG2_HIGHADDR = 0xBFFFFFFF
-               PARAMETER C_RNG3_BASEADDR = 0xC0000000
-               PARAMETER C_RNG3_HIGHADDR = 0xDFFFFFFF
-               BUS_INTERFACE SPLB = plb_v34_0
-               BUS_INTERFACE MOPB = opb_v20_0
-       END
-
-   Gives this device tree (some properties removed for clarity):
-
-       plb@0 {
-               #address-cells = <1>;
-               #size-cells = <1>;
-               compatible = "xlnx,plb-v34-1.02.a";
-               device_type = "ibm,plb";
-               ranges; // 1:1 translation
-
-               plb_bram_if_cntrl_0: bram@ffff0000 {
-                       reg = <ffff0000 10000>;
-               }
-
-               opb@20000000 {
-                       #address-cells = <1>;
-                       #size-cells = <1>;
-                       ranges = <20000000 20000000 20000000
-                                 60000000 60000000 20000000
-                                 80000000 80000000 40000000
-                                 c0000000 c0000000 20000000>;
-
-                       opb_uart16550_0: serial@a0000000 {
-                               reg = <a00000000 2000>;
-                       };
-
-                       opb_intc_0: interrupt-controller@d1000fc0 {
-                               reg = <d1000fc0 20>;
-                       };
-               };
-       };
-
-   That covers the general approach to binding xilinx IP cores into the
-   device tree.  The following are bindings for specific devices:
-
-      i) Xilinx ML300 Framebuffer
-
-      Simple framebuffer device from the ML300 reference design (also on the
-      ML403 reference design as well as others).
-
-      Optional properties:
-       - resolution = <xres yres> : pixel resolution of framebuffer.  Some
-                                    implementations use a different resolution.
-                                    Default is <d#640 d#480>
-       - virt-resolution = <xvirt yvirt> : Size of framebuffer in memory.
-                                           Default is <d#1024 d#480>.
-       - rotate-display (empty) : rotate display 180 degrees.
-
-      ii) Xilinx SystemACE
-
-      The Xilinx SystemACE device is used to program FPGAs from an FPGA
-      bitstream stored on a CF card.  It can also be used as a generic CF
-      interface device.
-
-      Optional properties:
-       - 8-bit (empty) : Set this property for SystemACE in 8 bit mode
-
-      iii) Xilinx EMAC and Xilinx TEMAC
-
-      Xilinx Ethernet devices.  In addition to general xilinx properties
-      listed above, nodes for these devices should include a phy-handle
-      property, and may include other common network device properties
-      like local-mac-address.
-
-      iv) Xilinx Uartlite
-
-      Xilinx uartlite devices are simple fixed speed serial ports.
-
-      Required properties:
-       - current-speed : Baud rate of uartlite
-
-      v) Xilinx hwicap
-
-               Xilinx hwicap devices provide access to the configuration logic
-               of the FPGA through the Internal Configuration Access Port
-               (ICAP).  The ICAP enables partial reconfiguration of the FPGA,
-               readback of the configuration information, and some control over
-               'warm boots' of the FPGA fabric.
-
-               Required properties:
-               - xlnx,family : The family of the FPGA, necessary since the
-                      capabilities of the underlying ICAP hardware
-                      differ between different families.  May be
-                      'virtex2p', 'virtex4', or 'virtex5'.
-
-      vi) Xilinx Uart 16550
-
-      Xilinx UART 16550 devices are very similar to the NS16550 but with
-      different register spacing and an offset from the base address.
-
-      Required properties:
-       - clock-frequency : Frequency of the clock input
-       - reg-offset : A value of 3 is required
-       - reg-shift : A value of 2 is required
-
-    e) USB EHCI controllers
-
-    Required properties:
-      - compatible : should be "usb-ehci".
-      - reg : should contain at least address and length of the standard EHCI
-        register set for the device. Optional platform-dependent registers
-        (debug-port or other) can be also specified here, but only after
-        definition of standard EHCI registers.
-      - interrupts : one EHCI interrupt should be described here.
-    If device registers are implemented in big endian mode, the device
-    node should have "big-endian-regs" property.
-    If controller implementation operates with big endian descriptors,
-    "big-endian-desc" property should be specified.
-    If both big endian registers and descriptors are used by the controller
-    implementation, "big-endian" property can be specified instead of having
-    both "big-endian-regs" and "big-endian-desc".
-
-     Example (Sequoia 440EPx):
-           ehci@e0000300 {
-                  compatible = "ibm,usb-ehci-440epx", "usb-ehci";
-                  interrupt-parent = <&UIC0>;
-                  interrupts = <1a 4>;
-                  reg = <0 e0000300 90 0 e0000390 70>;
-                  big-endian;
-          };
-
-   f) MDIO on GPIOs
-
-   Currently defined compatibles:
-   - virtual,gpio-mdio
-
-   MDC and MDIO lines connected to GPIO controllers are listed in the
-   gpios property as described in section VIII.1 in the following order:
-
-   MDC, MDIO.
-
-   Example:
-
-       mdio {
-               compatible = "virtual,mdio-gpio";
-               #address-cells = <1>;
-               #size-cells = <0>;
-               gpios = <&qe_pio_a 11
-                        &qe_pio_c 6>;
-       };
-
-    g) SPI (Serial Peripheral Interface) busses
-
-    SPI busses can be described with a node for the SPI master device
-    and a set of child nodes for each SPI slave on the bus.  For this
-    discussion, it is assumed that the system's SPI controller is in
-    SPI master mode.  This binding does not describe SPI controllers
-    in slave mode.
-
-    The SPI master node requires the following properties:
-    - #address-cells  - number of cells required to define a chip select
-                       address on the SPI bus.
-    - #size-cells     - should be zero.
-    - compatible      - name of SPI bus controller following generic names
-                       recommended practice.
-    No other properties are required in the SPI bus node.  It is assumed
-    that a driver for an SPI bus device will understand that it is an SPI bus.
-    However, the binding does not attempt to define the specific method for
-    assigning chip select numbers.  Since SPI chip select configuration is
-    flexible and non-standardized, it is left out of this binding with the
-    assumption that board specific platform code will be used to manage
-    chip selects.  Individual drivers can define additional properties to
-    support describing the chip select layout.
-
-    SPI slave nodes must be children of the SPI master node and can
-    contain the following properties.
-    - reg             - (required) chip select address of device.
-    - compatible      - (required) name of SPI device following generic names
-                       recommended practice
-    - spi-max-frequency - (required) Maximum SPI clocking speed of device in Hz
-    - spi-cpol        - (optional) Empty property indicating device requires
-                       inverse clock polarity (CPOL) mode
-    - spi-cpha        - (optional) Empty property indicating device requires
-                       shifted clock phase (CPHA) mode
-    - spi-cs-high     - (optional) Empty property indicating device requires
-                       chip select active high
-
-    SPI example for an MPC5200 SPI bus:
-               spi@f00 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       compatible = "fsl,mpc5200b-spi","fsl,mpc5200-spi";
-                       reg = <0xf00 0x20>;
-                       interrupts = <2 13 0 2 14 0>;
-                       interrupt-parent = <&mpc5200_pic>;
-
-                       ethernet-switch@0 {
-                               compatible = "micrel,ks8995m";
-                               spi-max-frequency = <1000000>;
-                               reg = <0>;
-                       };
-
-                       codec@1 {
-                               compatible = "ti,tlv320aic26";
-                               spi-max-frequency = <100000>;
-                               reg = <1>;
-                       };
-               };
-
-VII - Marvell Discovery mv64[345]6x System Controller chips
-===========================================================
-
-The Marvell mv64[345]60 series of system controller chips contain
-many of the peripherals needed to implement a complete computer
-system.  In this section, we define device tree nodes to describe
-the system controller chip itself and each of the peripherals
-which it contains.  Compatible string values for each node are
-prefixed with the string "marvell,", for Marvell Technology Group Ltd.
-
-1) The /system-controller node
-
-  This node is used to represent the system-controller and must be
-  present when the system uses a system controller chip. The top-level
-  system-controller node contains information that is global to all
-  devices within the system controller chip. The node name begins
-  with "system-controller" followed by the unit address, which is
-  the base address of the memory-mapped register set for the system
-  controller chip.
-
-  Required properties:
-
-    - ranges : Describes the translation of system controller addresses
-      for memory mapped registers.
-    - clock-frequency: Contains the main clock frequency for the system
-      controller chip.
-    - reg : This property defines the address and size of the
-      memory-mapped registers contained within the system controller
-      chip.  The address specified in the "reg" property should match
-      the unit address of the system-controller node.
-    - #address-cells : Address representation for system controller
-      devices.  This field represents the number of cells needed to
-      represent the address of the memory-mapped registers of devices
-      within the system controller chip.
-    - #size-cells : Size representation for for the memory-mapped
-      registers within the system controller chip.
-    - #interrupt-cells : Defines the width of cells used to represent
-      interrupts.
-
-  Optional properties:
-
-    - model : The specific model of the system controller chip.  Such
-      as, "mv64360", "mv64460", or "mv64560".
-    - compatible : A string identifying the compatibility identifiers
-      of the system controller chip.
-
-  The system-controller node contains child nodes for each system
-  controller device that the platform uses.  Nodes should not be created
-  for devices which exist on the system controller chip but are not used
-
-  Example Marvell Discovery mv64360 system-controller node:
-
-    system-controller@f1000000 { /* Marvell Discovery mv64360 */
-           #address-cells = <1>;
-           #size-cells = <1>;
-           model = "mv64360";                      /* Default */
-           compatible = "marvell,mv64360";
-           clock-frequency = <133333333>;
-           reg = <0xf1000000 0x10000>;
-           virtual-reg = <0xf1000000>;
-           ranges = <0x88000000 0x88000000 0x1000000 /* PCI 0 I/O Space */
-                   0x80000000 0x80000000 0x8000000 /* PCI 0 MEM Space */
-                   0xa0000000 0xa0000000 0x4000000 /* User FLASH */
-                   0x00000000 0xf1000000 0x0010000 /* Bridge's regs */
-                   0xf2000000 0xf2000000 0x0040000>;/* Integrated SRAM */
-
-           [ child node definitions... ]
-    }
-
-2) Child nodes of /system-controller
-
-   a) Marvell Discovery MDIO bus
-
-   The MDIO is a bus to which the PHY devices are connected.  For each
-   device that exists on this bus, a child node should be created.  See
-   the definition of the PHY node below for an example of how to define
-   a PHY.
-
-   Required properties:
-     - #address-cells : Should be <1>
-     - #size-cells : Should be <0>
-     - device_type : Should be "mdio"
-     - compatible : Should be "marvell,mv64360-mdio"
-
-   Example:
-
-     mdio {
-            #address-cells = <1>;
-            #size-cells = <0>;
-            device_type = "mdio";
-            compatible = "marvell,mv64360-mdio";
-
-            ethernet-phy@0 {
-                    ......
-            };
-     };
-
-
-   b) Marvell Discovery ethernet controller
-
-   The Discover ethernet controller is described with two levels
-   of nodes.  The first level describes an ethernet silicon block
-   and the second level describes up to 3 ethernet nodes within
-   that block.  The reason for the multiple levels is that the
-   registers for the node are interleaved within a single set
-   of registers.  The "ethernet-block" level describes the
-   shared register set, and the "ethernet" nodes describe ethernet
-   port-specific properties.
-
-   Ethernet block node
-
-   Required properties:
-     - #address-cells : <1>
-     - #size-cells : <0>
-     - compatible : "marvell,mv64360-eth-block"
-     - reg : Offset and length of the register set for this block
-
-   Example Discovery Ethernet block node:
-     ethernet-block@2000 {
-            #address-cells = <1>;
-            #size-cells = <0>;
-            compatible = "marvell,mv64360-eth-block";
-            reg = <0x2000 0x2000>;
-            ethernet@0 {
-                    .......
-            };
-     };
-
-   Ethernet port node
-
-   Required properties:
-     - device_type : Should be "network".
-     - compatible : Should be "marvell,mv64360-eth".
-     - reg : Should be <0>, <1>, or <2>, according to which registers
-       within the silicon block the device uses.
-     - interrupts : <a> where a is the interrupt number for the port.
-     - interrupt-parent : the phandle for the interrupt controller
-       that services interrupts for this device.
-     - phy : the phandle for the PHY connected to this ethernet
-       controller.
-     - local-mac-address : 6 bytes, MAC address
-
-   Example Discovery Ethernet port node:
-     ethernet@0 {
-            device_type = "network";
-            compatible = "marvell,mv64360-eth";
-            reg = <0>;
-            interrupts = <32>;
-            interrupt-parent = <&PIC>;
-            phy = <&PHY0>;
-            local-mac-address = [ 00 00 00 00 00 00 ];
-     };
-
-
-
-   c) Marvell Discovery PHY nodes
-
-   Required properties:
-     - device_type : Should be "ethernet-phy"
-     - interrupts : <a> where a is the interrupt number for this phy.
-     - interrupt-parent : the phandle for the interrupt controller that
-       services interrupts for this device.
-     - reg : The ID number for the phy, usually a small integer
-
-   Example Discovery PHY node:
-     ethernet-phy@1 {
-            device_type = "ethernet-phy";
-            compatible = "broadcom,bcm5421";
-            interrupts = <76>;      /* GPP 12 */
-            interrupt-parent = <&PIC>;
-            reg = <1>;
-     };
-
-
-   d) Marvell Discovery SDMA nodes
-
-   Represent DMA hardware associated with the MPSC (multiprotocol
-   serial controllers).
-
-   Required properties:
-     - compatible : "marvell,mv64360-sdma"
-     - reg : Offset and length of the register set for this device
-     - interrupts : <a> where a is the interrupt number for the DMA
-       device.
-     - interrupt-parent : the phandle for the interrupt controller
-       that services interrupts for this device.
-
-   Example Discovery SDMA node:
-     sdma@4000 {
-            compatible = "marvell,mv64360-sdma";
-            reg = <0x4000 0xc18>;
-            virtual-reg = <0xf1004000>;
-            interrupts = <36>;
-            interrupt-parent = <&PIC>;
-     };
-
-
-   e) Marvell Discovery BRG nodes
-
-   Represent baud rate generator hardware associated with the MPSC
-   (multiprotocol serial controllers).
-
-   Required properties:
-     - compatible : "marvell,mv64360-brg"
-     - reg : Offset and length of the register set for this device
-     - clock-src : A value from 0 to 15 which selects the clock
-       source for the baud rate generator.  This value corresponds
-       to the CLKS value in the BRGx configuration register.  See
-       the mv64x60 User's Manual.
-     - clock-frequence : The frequency (in Hz) of the baud rate
-       generator's input clock.
-     - current-speed : The current speed setting (presumably by
-       firmware) of the baud rate generator.
-
-   Example Discovery BRG node:
-     brg@b200 {
-            compatible = "marvell,mv64360-brg";
-            reg = <0xb200 0x8>;
-            clock-src = <8>;
-            clock-frequency = <133333333>;
-            current-speed = <9600>;
-     };
-
-
-   f) Marvell Discovery CUNIT nodes
-
-   Represent the Serial Communications Unit device hardware.
-
-   Required properties:
-     - reg : Offset and length of the register set for this device
-
-   Example Discovery CUNIT node:
-     cunit@f200 {
-            reg = <0xf200 0x200>;
-     };
-
-
-   g) Marvell Discovery MPSCROUTING nodes
-
-   Represent the Discovery's MPSC routing hardware
-
-   Required properties:
-     - reg : Offset and length of the register set for this device
-
-   Example Discovery CUNIT node:
-     mpscrouting@b500 {
-            reg = <0xb400 0xc>;
-     };
-
-
-   h) Marvell Discovery MPSCINTR nodes
-
-   Represent the Discovery's MPSC DMA interrupt hardware registers
-   (SDMA cause and mask registers).
-
-   Required properties:
-     - reg : Offset and length of the register set for this device
-
-   Example Discovery MPSCINTR node:
-     mpsintr@b800 {
-            reg = <0xb800 0x100>;
-     };
-
-
-   i) Marvell Discovery MPSC nodes
-
-   Represent the Discovery's MPSC (Multiprotocol Serial Controller)
-   serial port.
-
-   Required properties:
-     - device_type : "serial"
-     - compatible : "marvell,mv64360-mpsc"
-     - reg : Offset and length of the register set for this device
-     - sdma : the phandle for the SDMA node used by this port
-     - brg : the phandle for the BRG node used by this port
-     - cunit : the phandle for the CUNIT node used by this port
-     - mpscrouting : the phandle for the MPSCROUTING node used by this port
-     - mpscintr : the phandle for the MPSCINTR node used by this port
-     - cell-index : the hardware index of this cell in the MPSC core
-     - max_idle : value needed for MPSC CHR3 (Maximum Frame Length)
-       register
-     - interrupts : <a> where a is the interrupt number for the MPSC.
-     - interrupt-parent : the phandle for the interrupt controller
-       that services interrupts for this device.
-
-   Example Discovery MPSCINTR node:
-     mpsc@8000 {
-            device_type = "serial";
-            compatible = "marvell,mv64360-mpsc";
-            reg = <0x8000 0x38>;
-            virtual-reg = <0xf1008000>;
-            sdma = <&SDMA0>;
-            brg = <&BRG0>;
-            cunit = <&CUNIT>;
-            mpscrouting = <&MPSCROUTING>;
-            mpscintr = <&MPSCINTR>;
-            cell-index = <0>;
-            max_idle = <40>;
-            interrupts = <40>;
-            interrupt-parent = <&PIC>;
-     };
-
-
-   j) Marvell Discovery Watch Dog Timer nodes
-
-   Represent the Discovery's watchdog timer hardware
-
-   Required properties:
-     - compatible : "marvell,mv64360-wdt"
-     - reg : Offset and length of the register set for this device
-
-   Example Discovery Watch Dog Timer node:
-     wdt@b410 {
-            compatible = "marvell,mv64360-wdt";
-            reg = <0xb410 0x8>;
-     };
-
-
-   k) Marvell Discovery I2C nodes
-
-   Represent the Discovery's I2C hardware
-
-   Required properties:
-     - device_type : "i2c"
-     - compatible : "marvell,mv64360-i2c"
-     - reg : Offset and length of the register set for this device
-     - interrupts : <a> where a is the interrupt number for the I2C.
-     - interrupt-parent : the phandle for the interrupt controller
-       that services interrupts for this device.
-
-   Example Discovery I2C node:
-            compatible = "marvell,mv64360-i2c";
-            reg = <0xc000 0x20>;
-            virtual-reg = <0xf100c000>;
-            interrupts = <37>;
-            interrupt-parent = <&PIC>;
-     };
-
-
-   l) Marvell Discovery PIC (Programmable Interrupt Controller) nodes
-
-   Represent the Discovery's PIC hardware
-
-   Required properties:
-     - #interrupt-cells : <1>
-     - #address-cells : <0>
-     - compatible : "marvell,mv64360-pic"
-     - reg : Offset and length of the register set for this device
-     - interrupt-controller
-
-   Example Discovery PIC node:
-     pic {
-            #interrupt-cells = <1>;
-            #address-cells = <0>;
-            compatible = "marvell,mv64360-pic";
-            reg = <0x0 0x88>;
-            interrupt-controller;
-     };
-
-
-   m) Marvell Discovery MPP (Multipurpose Pins) multiplexing nodes
-
-   Represent the Discovery's MPP hardware
-
-   Required properties:
-     - compatible : "marvell,mv64360-mpp"
-     - reg : Offset and length of the register set for this device
-
-   Example Discovery MPP node:
-     mpp@f000 {
-            compatible = "marvell,mv64360-mpp";
-            reg = <0xf000 0x10>;
-     };
-
-
-   n) Marvell Discovery GPP (General Purpose Pins) nodes
-
-   Represent the Discovery's GPP hardware
-
-   Required properties:
-     - compatible : "marvell,mv64360-gpp"
-     - reg : Offset and length of the register set for this device
-
-   Example Discovery GPP node:
-     gpp@f000 {
-            compatible = "marvell,mv64360-gpp";
-            reg = <0xf100 0x20>;
-     };
-
-
-   o) Marvell Discovery PCI host bridge node
-
-   Represents the Discovery's PCI host bridge device.  The properties
-   for this node conform to Rev 2.1 of the PCI Bus Binding to IEEE
-   1275-1994.  A typical value for the compatible property is
-   "marvell,mv64360-pci".
-
-   Example Discovery PCI host bridge node
-     pci@80000000 {
-            #address-cells = <3>;
-            #size-cells = <2>;
-            #interrupt-cells = <1>;
-            device_type = "pci";
-            compatible = "marvell,mv64360-pci";
-            reg = <0xcf8 0x8>;
-            ranges = <0x01000000 0x0        0x0
-                            0x88000000 0x0 0x01000000
-                      0x02000000 0x0 0x80000000
-                            0x80000000 0x0 0x08000000>;
-            bus-range = <0 255>;
-            clock-frequency = <66000000>;
-            interrupt-parent = <&PIC>;
-            interrupt-map-mask = <0xf800 0x0 0x0 0x7>;
-            interrupt-map = <
-                    /* IDSEL 0x0a */
-                    0x5000 0 0 1 &PIC 80
-                    0x5000 0 0 2 &PIC 81
-                    0x5000 0 0 3 &PIC 91
-                    0x5000 0 0 4 &PIC 93
-
-                    /* IDSEL 0x0b */
-                    0x5800 0 0 1 &PIC 91
-                    0x5800 0 0 2 &PIC 93
-                    0x5800 0 0 3 &PIC 80
-                    0x5800 0 0 4 &PIC 81
-
-                    /* IDSEL 0x0c */
-                    0x6000 0 0 1 &PIC 91
-                    0x6000 0 0 2 &PIC 93
-                    0x6000 0 0 3 &PIC 80
-                    0x6000 0 0 4 &PIC 81
-
-                    /* IDSEL 0x0d */
-                    0x6800 0 0 1 &PIC 93
-                    0x6800 0 0 2 &PIC 80
-                    0x6800 0 0 3 &PIC 81
-                    0x6800 0 0 4 &PIC 91
-            >;
-     };
-
-
-   p) Marvell Discovery CPU Error nodes
-
-   Represent the Discovery's CPU error handler device.
-
-   Required properties:
-     - compatible : "marvell,mv64360-cpu-error"
-     - reg : Offset and length of the register set for this device
-     - interrupts : the interrupt number for this device
-     - interrupt-parent : the phandle for the interrupt controller
-       that services interrupts for this device.
-
-   Example Discovery CPU Error node:
-     cpu-error@0070 {
-            compatible = "marvell,mv64360-cpu-error";
-            reg = <0x70 0x10 0x128 0x28>;
-            interrupts = <3>;
-            interrupt-parent = <&PIC>;
-     };
-
-
-   q) Marvell Discovery SRAM Controller nodes
-
-   Represent the Discovery's SRAM controller device.
-
-   Required properties:
-     - compatible : "marvell,mv64360-sram-ctrl"
-     - reg : Offset and length of the register set for this device
-     - interrupts : the interrupt number for this device
-     - interrupt-parent : the phandle for the interrupt controller
-       that services interrupts for this device.
-
-   Example Discovery SRAM Controller node:
-     sram-ctrl@0380 {
-            compatible = "marvell,mv64360-sram-ctrl";
-            reg = <0x380 0x80>;
-            interrupts = <13>;
-            interrupt-parent = <&PIC>;
-     };
-
-
-   r) Marvell Discovery PCI Error Handler nodes
-
-   Represent the Discovery's PCI error handler device.
-
-   Required properties:
-     - compatible : "marvell,mv64360-pci-error"
-     - reg : Offset and length of the register set for this device
-     - interrupts : the interrupt number for this device
-     - interrupt-parent : the phandle for the interrupt controller
-       that services interrupts for this device.
-
-   Example Discovery PCI Error Handler node:
-     pci-error@1d40 {
-            compatible = "marvell,mv64360-pci-error";
-            reg = <0x1d40 0x40 0xc28 0x4>;
-            interrupts = <12>;
-            interrupt-parent = <&PIC>;
-     };
-
-
-   s) Marvell Discovery Memory Controller nodes
-
-   Represent the Discovery's memory controller device.
-
-   Required properties:
-     - compatible : "marvell,mv64360-mem-ctrl"
-     - reg : Offset and length of the register set for this device
-     - interrupts : the interrupt number for this device
-     - interrupt-parent : the phandle for the interrupt controller
-       that services interrupts for this device.
-
-   Example Discovery Memory Controller node:
-     mem-ctrl@1400 {
-            compatible = "marvell,mv64360-mem-ctrl";
-            reg = <0x1400 0x60>;
-            interrupts = <17>;
-            interrupt-parent = <&PIC>;
-     };
-
-
-VIII - Specifying interrupt information for devices
+VII - Specifying interrupt information for devices
 ===================================================
 
 The device tree represents the busses and devices of a hardware
@@ -2439,56 +1324,7 @@ encodings listed below:
        2 =  high to low edge sensitive type enabled
        3 =  low to high edge sensitive type enabled
 
-IX - Specifying GPIO information for devices
-============================================
-
-1) gpios property
------------------
-
-Nodes that makes use of GPIOs should define them using `gpios' property,
-format of which is: <&gpio-controller1-phandle gpio1-specifier
-                    &gpio-controller2-phandle gpio2-specifier
-                    0 /* holes are permitted, means no GPIO 3 */
-                    &gpio-controller4-phandle gpio4-specifier
-                    ...>;
-
-Note that gpio-specifier length is controller dependent.
-
-gpio-specifier may encode: bank, pin position inside the bank,
-whether pin is open-drain and whether pin is logically inverted.
-
-Example of the node using GPIOs:
-
-       node {
-               gpios = <&qe_pio_e 18 0>;
-       };
-
-In this example gpio-specifier is "18 0" and encodes GPIO pin number,
-and empty GPIO flags as accepted by the "qe_pio_e" gpio-controller.
-
-2) gpio-controller nodes
-------------------------
-
-Every GPIO controller node must have #gpio-cells property defined,
-this information will be used to translate gpio-specifiers.
-
-Example of two SOC GPIO banks defined as gpio-controller nodes:
-
-       qe_pio_a: gpio-controller@1400 {
-               #gpio-cells = <2>;
-               compatible = "fsl,qe-pario-bank-a", "fsl,qe-pario-bank";
-               reg = <0x1400 0x18>;
-               gpio-controller;
-       };
-
-       qe_pio_e: gpio-controller@1460 {
-               #gpio-cells = <2>;
-               compatible = "fsl,qe-pario-bank-e", "fsl,qe-pario-bank";
-               reg = <0x1460 0x18>;
-               gpio-controller;
-       };
-
-X - Specifying Device Power Management Information (sleep property)
+VIII - Specifying Device Power Management Information (sleep property)
 ===================================================================
 
 Devices on SOCs often have mechanisms for placing devices into low-power
diff --git a/Documentation/powerpc/dts-bindings/4xx/emac.txt b/Documentation/powerpc/dts-bindings/4xx/emac.txt
new file mode 100644 (file)
index 0000000..2161334
--- /dev/null
@@ -0,0 +1,148 @@
+    4xx/Axon EMAC ethernet nodes
+
+    The EMAC ethernet controller in IBM and AMCC 4xx chips, and also
+    the Axon bridge.  To operate this needs to interact with a ths
+    special McMAL DMA controller, and sometimes an RGMII or ZMII
+    interface.  In addition to the nodes and properties described
+    below, the node for the OPB bus on which the EMAC sits must have a
+    correct clock-frequency property.
+
+      i) The EMAC node itself
+
+    Required properties:
+    - device_type       : "network"
+
+    - compatible        : compatible list, contains 2 entries, first is
+                         "ibm,emac-CHIP" where CHIP is the host ASIC (440gx,
+                         405gp, Axon) and second is either "ibm,emac" or
+                         "ibm,emac4".  For Axon, thus, we have: "ibm,emac-axon",
+                         "ibm,emac4"
+    - interrupts        : <interrupt mapping for EMAC IRQ and WOL IRQ>
+    - interrupt-parent  : optional, if needed for interrupt mapping
+    - reg               : <registers mapping>
+    - local-mac-address : 6 bytes, MAC address
+    - mal-device        : phandle of the associated McMAL node
+    - mal-tx-channel    : 1 cell, index of the tx channel on McMAL associated
+                         with this EMAC
+    - mal-rx-channel    : 1 cell, index of the rx channel on McMAL associated
+                         with this EMAC
+    - cell-index        : 1 cell, hardware index of the EMAC cell on a given
+                         ASIC (typically 0x0 and 0x1 for EMAC0 and EMAC1 on
+                         each Axon chip)
+    - max-frame-size    : 1 cell, maximum frame size supported in bytes
+    - rx-fifo-size      : 1 cell, Rx fifo size in bytes for 10 and 100 Mb/sec
+                         operations.
+                         For Axon, 2048
+    - tx-fifo-size      : 1 cell, Tx fifo size in bytes for 10 and 100 Mb/sec
+                         operations.
+                         For Axon, 2048.
+    - fifo-entry-size   : 1 cell, size of a fifo entry (used to calculate
+                         thresholds).
+                         For Axon, 0x00000010
+    - mal-burst-size    : 1 cell, MAL burst size (used to calculate thresholds)
+                         in bytes.
+                         For Axon, 0x00000100 (I think ...)
+    - phy-mode          : string, mode of operations of the PHY interface.
+                         Supported values are: "mii", "rmii", "smii", "rgmii",
+                         "tbi", "gmii", rtbi", "sgmii".
+                         For Axon on CAB, it is "rgmii"
+    - mdio-device       : 1 cell, required iff using shared MDIO registers
+                         (440EP).  phandle of the EMAC to use to drive the
+                         MDIO lines for the PHY used by this EMAC.
+    - zmii-device       : 1 cell, required iff connected to a ZMII.  phandle of
+                         the ZMII device node
+    - zmii-channel      : 1 cell, required iff connected to a ZMII.  Which ZMII
+                         channel or 0xffffffff if ZMII is only used for MDIO.
+    - rgmii-device      : 1 cell, required iff connected to an RGMII. phandle
+                         of the RGMII device node.
+                         For Axon: phandle of plb5/plb4/opb/rgmii
+    - rgmii-channel     : 1 cell, required iff connected to an RGMII.  Which
+                         RGMII channel is used by this EMAC.
+                         Fox Axon: present, whatever value is appropriate for each
+                         EMAC, that is the content of the current (bogus) "phy-port"
+                         property.
+
+    Optional properties:
+    - phy-address       : 1 cell, optional, MDIO address of the PHY. If absent,
+                         a search is performed.
+    - phy-map           : 1 cell, optional, bitmap of addresses to probe the PHY
+                         for, used if phy-address is absent. bit 0x00000001 is
+                         MDIO address 0.
+                         For Axon it can be absent, though my current driver
+                         doesn't handle phy-address yet so for now, keep
+                         0x00ffffff in it.
+    - rx-fifo-size-gige : 1 cell, Rx fifo size in bytes for 1000 Mb/sec
+                         operations (if absent the value is the same as
+                         rx-fifo-size).  For Axon, either absent or 2048.
+    - tx-fifo-size-gige : 1 cell, Tx fifo size in bytes for 1000 Mb/sec
+                         operations (if absent the value is the same as
+                         tx-fifo-size). For Axon, either absent or 2048.
+    - tah-device        : 1 cell, optional. If connected to a TAH engine for
+                         offload, phandle of the TAH device node.
+    - tah-channel       : 1 cell, optional. If appropriate, channel used on the
+                         TAH engine.
+
+    Example:
+
+       EMAC0: ethernet@40000800 {
+               device_type = "network";
+               compatible = "ibm,emac-440gp", "ibm,emac";
+               interrupt-parent = <&UIC1>;
+               interrupts = <1c 4 1d 4>;
+               reg = <40000800 70>;
+               local-mac-address = [00 04 AC E3 1B 1E];
+               mal-device = <&MAL0>;
+               mal-tx-channel = <0 1>;
+               mal-rx-channel = <0>;
+               cell-index = <0>;
+               max-frame-size = <5dc>;
+               rx-fifo-size = <1000>;
+               tx-fifo-size = <800>;
+               phy-mode = "rmii";
+               phy-map = <00000001>;
+               zmii-device = <&ZMII0>;
+               zmii-channel = <0>;
+       };
+
+      ii) McMAL node
+
+    Required properties:
+    - device_type        : "dma-controller"
+    - compatible         : compatible list, containing 2 entries, first is
+                          "ibm,mcmal-CHIP" where CHIP is the host ASIC (like
+                          emac) and the second is either "ibm,mcmal" or
+                          "ibm,mcmal2".
+                          For Axon, "ibm,mcmal-axon","ibm,mcmal2"
+    - interrupts         : <interrupt mapping for the MAL interrupts sources:
+                           5 sources: tx_eob, rx_eob, serr, txde, rxde>.
+                           For Axon: This is _different_ from the current
+                          firmware.  We use the "delayed" interrupts for txeob
+                          and rxeob. Thus we end up with mapping those 5 MPIC
+                          interrupts, all level positive sensitive: 10, 11, 32,
+                          33, 34 (in decimal)
+    - dcr-reg            : < DCR registers range >
+    - dcr-parent         : if needed for dcr-reg
+    - num-tx-chans       : 1 cell, number of Tx channels
+    - num-rx-chans       : 1 cell, number of Rx channels
+
+      iii) ZMII node
+
+    Required properties:
+    - compatible         : compatible list, containing 2 entries, first is
+                          "ibm,zmii-CHIP" where CHIP is the host ASIC (like
+                          EMAC) and the second is "ibm,zmii".
+                          For Axon, there is no ZMII node.
+    - reg                : <registers mapping>
+
+      iv) RGMII node
+
+    Required properties:
+    - compatible         : compatible list, containing 2 entries, first is
+                          "ibm,rgmii-CHIP" where CHIP is the host ASIC (like
+                          EMAC) and the second is "ibm,rgmii".
+                           For Axon, "ibm,rgmii-axon","ibm,rgmii"
+    - reg                : <registers mapping>
+    - revision           : as provided by the RGMII new version register if
+                          available.
+                          For Axon: 0x0000012a
+
diff --git a/Documentation/powerpc/dts-bindings/gpio/gpio.txt b/Documentation/powerpc/dts-bindings/gpio/gpio.txt
new file mode 100644 (file)
index 0000000..edaa84d
--- /dev/null
@@ -0,0 +1,50 @@
+Specifying GPIO information for devices
+============================================
+
+1) gpios property
+-----------------
+
+Nodes that makes use of GPIOs should define them using `gpios' property,
+format of which is: <&gpio-controller1-phandle gpio1-specifier
+                    &gpio-controller2-phandle gpio2-specifier
+                    0 /* holes are permitted, means no GPIO 3 */
+                    &gpio-controller4-phandle gpio4-specifier
+                    ...>;
+
+Note that gpio-specifier length is controller dependent.
+
+gpio-specifier may encode: bank, pin position inside the bank,
+whether pin is open-drain and whether pin is logically inverted.
+
+Example of the node using GPIOs:
+
+       node {
+               gpios = <&qe_pio_e 18 0>;
+       };
+
+In this example gpio-specifier is "18 0" and encodes GPIO pin number,
+and empty GPIO flags as accepted by the "qe_pio_e" gpio-controller.
+
+2) gpio-controller nodes
+------------------------
+
+Every GPIO controller node must have #gpio-cells property defined,
+this information will be used to translate gpio-specifiers.
+
+Example of two SOC GPIO banks defined as gpio-controller nodes:
+
+       qe_pio_a: gpio-controller@1400 {
+               #gpio-cells = <2>;
+               compatible = "fsl,qe-pario-bank-a", "fsl,qe-pario-bank";
+               reg = <0x1400 0x18>;
+               gpio-controller;
+       };
+
+       qe_pio_e: gpio-controller@1460 {
+               #gpio-cells = <2>;
+               compatible = "fsl,qe-pario-bank-e", "fsl,qe-pario-bank";
+               reg = <0x1460 0x18>;
+               gpio-controller;
+       };
+
+
index 4fe14de..064db92 100644 (file)
@@ -16,10 +16,17 @@ LED sub-node properties:
   string defining the trigger assigned to the LED.  Current triggers are:
     "backlight" - LED will act as a back-light, controlled by the framebuffer
                  system
-    "default-on" - LED will turn on
+    "default-on" - LED will turn on, but see "default-state" below
     "heartbeat" - LED "double" flashes at a load average based rate
     "ide-disk" - LED indicates disk activity
     "timer" - LED flashes at a fixed, configurable rate
+- default-state:  (optional) The initial state of the LED.  Valid
+  values are "on", "off", and "keep".  If the LED is already on or off
+  and the default-state property is set the to same value, then no
+  glitch should be produced where the LED momentarily turns off (or
+  on).  The "keep" setting will keep the LED at whatever its current
+  state is, without producing a glitch.  The default is off if this
+  property is not present.
 
 Examples:
 
@@ -30,14 +37,22 @@ leds {
                gpios = <&mcu_pio 0 1>; /* Active low */
                linux,default-trigger = "ide-disk";
        };
+
+       fault {
+               gpios = <&mcu_pio 1 0>;
+               /* Keep LED on if BIOS detected hardware fault */
+               default-state = "keep";
+       };
 };
 
 run-control {
        compatible = "gpio-leds";
        red {
                gpios = <&mpc8572 6 0>;
+               default-state = "off";
        };
        green {
                gpios = <&mpc8572 7 0>;
+               default-state = "on";
        };
 }
diff --git a/Documentation/powerpc/dts-bindings/gpio/mdio.txt b/Documentation/powerpc/dts-bindings/gpio/mdio.txt
new file mode 100644 (file)
index 0000000..bc95495
--- /dev/null
@@ -0,0 +1,19 @@
+MDIO on GPIOs
+
+Currently defined compatibles:
+- virtual,gpio-mdio
+
+MDC and MDIO lines connected to GPIO controllers are listed in the
+gpios property as described in section VIII.1 in the following order:
+
+MDC, MDIO.
+
+Example:
+
+mdio {
+       compatible = "virtual,mdio-gpio";
+       #address-cells = <1>;
+       #size-cells = <0>;
+       gpios = <&qe_pio_a 11
+                &qe_pio_c 6>;
+};
diff --git a/Documentation/powerpc/dts-bindings/marvell.txt b/Documentation/powerpc/dts-bindings/marvell.txt
new file mode 100644 (file)
index 0000000..3708a2f
--- /dev/null
@@ -0,0 +1,521 @@
+Marvell Discovery mv64[345]6x System Controller chips
+===========================================================
+
+The Marvell mv64[345]60 series of system controller chips contain
+many of the peripherals needed to implement a complete computer
+system.  In this section, we define device tree nodes to describe
+the system controller chip itself and each of the peripherals
+which it contains.  Compatible string values for each node are
+prefixed with the string "marvell,", for Marvell Technology Group Ltd.
+
+1) The /system-controller node
+
+  This node is used to represent the system-controller and must be
+  present when the system uses a system controller chip. The top-level
+  system-controller node contains information that is global to all
+  devices within the system controller chip. The node name begins
+  with "system-controller" followed by the unit address, which is
+  the base address of the memory-mapped register set for the system
+  controller chip.
+
+  Required properties:
+
+    - ranges : Describes the translation of system controller addresses
+      for memory mapped registers.
+    - clock-frequency: Contains the main clock frequency for the system
+      controller chip.
+    - reg : This property defines the address and size of the
+      memory-mapped registers contained within the system controller
+      chip.  The address specified in the "reg" property should match
+      the unit address of the system-controller node.
+    - #address-cells : Address representation for system controller
+      devices.  This field represents the number of cells needed to
+      represent the address of the memory-mapped registers of devices
+      within the system controller chip.
+    - #size-cells : Size representation for for the memory-mapped
+      registers within the system controller chip.
+    - #interrupt-cells : Defines the width of cells used to represent
+      interrupts.
+
+  Optional properties:
+
+    - model : The specific model of the system controller chip.  Such
+      as, "mv64360", "mv64460", or "mv64560".
+    - compatible : A string identifying the compatibility identifiers
+      of the system controller chip.
+
+  The system-controller node contains child nodes for each system
+  controller device that the platform uses.  Nodes should not be created
+  for devices which exist on the system controller chip but are not used
+
+  Example Marvell Discovery mv64360 system-controller node:
+
+    system-controller@f1000000 { /* Marvell Discovery mv64360 */
+           #address-cells = <1>;
+           #size-cells = <1>;
+           model = "mv64360";                      /* Default */
+           compatible = "marvell,mv64360";
+           clock-frequency = <133333333>;
+           reg = <0xf1000000 0x10000>;
+           virtual-reg = <0xf1000000>;
+           ranges = <0x88000000 0x88000000 0x1000000 /* PCI 0 I/O Space */
+                   0x80000000 0x80000000 0x8000000 /* PCI 0 MEM Space */
+                   0xa0000000 0xa0000000 0x4000000 /* User FLASH */
+                   0x00000000 0xf1000000 0x0010000 /* Bridge's regs */
+                   0xf2000000 0xf2000000 0x0040000>;/* Integrated SRAM */
+
+           [ child node definitions... ]
+    }
+
+2) Child nodes of /system-controller
+
+   a) Marvell Discovery MDIO bus
+
+   The MDIO is a bus to which the PHY devices are connected.  For each
+   device that exists on this bus, a child node should be created.  See
+   the definition of the PHY node below for an example of how to define
+   a PHY.
+
+   Required properties:
+     - #address-cells : Should be <1>
+     - #size-cells : Should be <0>
+     - device_type : Should be "mdio"
+     - compatible : Should be "marvell,mv64360-mdio"
+
+   Example:
+
+     mdio {
+            #address-cells = <1>;
+            #size-cells = <0>;
+            device_type = "mdio";
+            compatible = "marvell,mv64360-mdio";
+
+            ethernet-phy@0 {
+                    ......
+            };
+     };
+
+
+   b) Marvell Discovery ethernet controller
+
+   The Discover ethernet controller is described with two levels
+   of nodes.  The first level describes an ethernet silicon block
+   and the second level describes up to 3 ethernet nodes within
+   that block.  The reason for the multiple levels is that the
+   registers for the node are interleaved within a single set
+   of registers.  The "ethernet-block" level describes the
+   shared register set, and the "ethernet" nodes describe ethernet
+   port-specific properties.
+
+   Ethernet block node
+
+   Required properties:
+     - #address-cells : <1>
+     - #size-cells : <0>
+     - compatible : "marvell,mv64360-eth-block"
+     - reg : Offset and length of the register set for this block
+
+   Example Discovery Ethernet block node:
+     ethernet-block@2000 {
+            #address-cells = <1>;
+            #size-cells = <0>;
+            compatible = "marvell,mv64360-eth-block";
+            reg = <0x2000 0x2000>;
+            ethernet@0 {
+                    .......
+            };
+     };
+
+   Ethernet port node
+
+   Required properties:
+     - device_type : Should be "network".
+     - compatible : Should be "marvell,mv64360-eth".
+     - reg : Should be <0>, <1>, or <2>, according to which registers
+       within the silicon block the device uses.
+     - interrupts : <a> where a is the interrupt number for the port.
+     - interrupt-parent : the phandle for the interrupt controller
+       that services interrupts for this device.
+     - phy : the phandle for the PHY connected to this ethernet
+       controller.
+     - local-mac-address : 6 bytes, MAC address
+
+   Example Discovery Ethernet port node:
+     ethernet@0 {
+            device_type = "network";
+            compatible = "marvell,mv64360-eth";
+            reg = <0>;
+            interrupts = <32>;
+            interrupt-parent = <&PIC>;
+            phy = <&PHY0>;
+            local-mac-address = [ 00 00 00 00 00 00 ];
+     };
+
+
+
+   c) Marvell Discovery PHY nodes
+
+   Required properties:
+     - device_type : Should be "ethernet-phy"
+     - interrupts : <a> where a is the interrupt number for this phy.
+     - interrupt-parent : the phandle for the interrupt controller that
+       services interrupts for this device.
+     - reg : The ID number for the phy, usually a small integer
+
+   Example Discovery PHY node:
+     ethernet-phy@1 {
+            device_type = "ethernet-phy";
+            compatible = "broadcom,bcm5421";
+            interrupts = <76>;      /* GPP 12 */
+            interrupt-parent = <&PIC>;
+            reg = <1>;
+     };
+
+
+   d) Marvell Discovery SDMA nodes
+
+   Represent DMA hardware associated with the MPSC (multiprotocol
+   serial controllers).
+
+   Required properties:
+     - compatible : "marvell,mv64360-sdma"
+     - reg : Offset and length of the register set for this device
+     - interrupts : <a> where a is the interrupt number for the DMA
+       device.
+     - interrupt-parent : the phandle for the interrupt controller
+       that services interrupts for this device.
+
+   Example Discovery SDMA node:
+     sdma@4000 {
+            compatible = "marvell,mv64360-sdma";
+            reg = <0x4000 0xc18>;
+            virtual-reg = <0xf1004000>;
+            interrupts = <36>;
+            interrupt-parent = <&PIC>;
+     };
+
+
+   e) Marvell Discovery BRG nodes
+
+   Represent baud rate generator hardware associated with the MPSC
+   (multiprotocol serial controllers).
+
+   Required properties:
+     - compatible : "marvell,mv64360-brg"
+     - reg : Offset and length of the register set for this device
+     - clock-src : A value from 0 to 15 which selects the clock
+       source for the baud rate generator.  This value corresponds
+       to the CLKS value in the BRGx configuration register.  See
+       the mv64x60 User's Manual.
+     - clock-frequence : The frequency (in Hz) of the baud rate
+       generator's input clock.
+     - current-speed : The current speed setting (presumably by
+       firmware) of the baud rate generator.
+
+   Example Discovery BRG node:
+     brg@b200 {
+            compatible = "marvell,mv64360-brg";
+            reg = <0xb200 0x8>;
+            clock-src = <8>;
+            clock-frequency = <133333333>;
+            current-speed = <9600>;
+     };
+
+
+   f) Marvell Discovery CUNIT nodes
+
+   Represent the Serial Communications Unit device hardware.
+
+   Required properties:
+     - reg : Offset and length of the register set for this device
+
+   Example Discovery CUNIT node:
+     cunit@f200 {
+            reg = <0xf200 0x200>;
+     };
+
+
+   g) Marvell Discovery MPSCROUTING nodes
+
+   Represent the Discovery's MPSC routing hardware
+
+   Required properties:
+     - reg : Offset and length of the register set for this device
+
+   Example Discovery CUNIT node:
+     mpscrouting@b500 {
+            reg = <0xb400 0xc>;
+     };
+
+
+   h) Marvell Discovery MPSCINTR nodes
+
+   Represent the Discovery's MPSC DMA interrupt hardware registers
+   (SDMA cause and mask registers).
+
+   Required properties:
+     - reg : Offset and length of the register set for this device
+
+   Example Discovery MPSCINTR node:
+     mpsintr@b800 {
+            reg = <0xb800 0x100>;
+     };
+
+
+   i) Marvell Discovery MPSC nodes
+
+   Represent the Discovery's MPSC (Multiprotocol Serial Controller)
+   serial port.
+
+   Required properties:
+     - device_type : "serial"
+     - compatible : "marvell,mv64360-mpsc"
+     - reg : Offset and length of the register set for this device
+     - sdma : the phandle for the SDMA node used by this port
+     - brg : the phandle for the BRG node used by this port
+     - cunit : the phandle for the CUNIT node used by this port
+     - mpscrouting : the phandle for the MPSCROUTING node used by this port
+     - mpscintr : the phandle for the MPSCINTR node used by this port
+     - cell-index : the hardware index of this cell in the MPSC core
+     - max_idle : value needed for MPSC CHR3 (Maximum Frame Length)
+       register
+     - interrupts : <a> where a is the interrupt number for the MPSC.
+     - interrupt-parent : the phandle for the interrupt controller
+       that services interrupts for this device.
+
+   Example Discovery MPSCINTR node:
+     mpsc@8000 {
+            device_type = "serial";
+            compatible = "marvell,mv64360-mpsc";
+            reg = <0x8000 0x38>;
+            virtual-reg = <0xf1008000>;
+            sdma = <&SDMA0>;
+            brg = <&BRG0>;
+            cunit = <&CUNIT>;
+            mpscrouting = <&MPSCROUTING>;
+            mpscintr = <&MPSCINTR>;
+            cell-index = <0>;
+            max_idle = <40>;
+            interrupts = <40>;
+            interrupt-parent = <&PIC>;
+     };
+
+
+   j) Marvell Discovery Watch Dog Timer nodes
+
+   Represent the Discovery's watchdog timer hardware
+
+   Required properties:
+     - compatible : "marvell,mv64360-wdt"
+     - reg : Offset and length of the register set for this device
+
+   Example Discovery Watch Dog Timer node:
+     wdt@b410 {
+            compatible = "marvell,mv64360-wdt";
+            reg = <0xb410 0x8>;
+     };
+
+
+   k) Marvell Discovery I2C nodes
+
+   Represent the Discovery's I2C hardware
+
+   Required properties:
+     - device_type : "i2c"
+     - compatible : "marvell,mv64360-i2c"
+     - reg : Offset and length of the register set for this device
+     - interrupts : <a> where a is the interrupt number for the I2C.
+     - interrupt-parent : the phandle for the interrupt controller
+       that services interrupts for this device.
+
+   Example Discovery I2C node:
+            compatible = "marvell,mv64360-i2c";
+            reg = <0xc000 0x20>;
+            virtual-reg = <0xf100c000>;
+            interrupts = <37>;
+            interrupt-parent = <&PIC>;
+     };
+
+
+   l) Marvell Discovery PIC (Programmable Interrupt Controller) nodes
+
+   Represent the Discovery's PIC hardware
+
+   Required properties:
+     - #interrupt-cells : <1>
+     - #address-cells : <0>
+     - compatible : "marvell,mv64360-pic"
+     - reg : Offset and length of the register set for this device
+     - interrupt-controller
+
+   Example Discovery PIC node:
+     pic {
+            #interrupt-cells = <1>;
+            #address-cells = <0>;
+            compatible = "marvell,mv64360-pic";
+            reg = <0x0 0x88>;
+            interrupt-controller;
+     };
+
+
+   m) Marvell Discovery MPP (Multipurpose Pins) multiplexing nodes
+
+   Represent the Discovery's MPP hardware
+
+   Required properties:
+     - compatible : "marvell,mv64360-mpp"
+     - reg : Offset and length of the register set for this device
+
+   Example Discovery MPP node:
+     mpp@f000 {
+            compatible = "marvell,mv64360-mpp";
+            reg = <0xf000 0x10>;
+     };
+
+
+   n) Marvell Discovery GPP (General Purpose Pins) nodes
+
+   Represent the Discovery's GPP hardware
+
+   Required properties:
+     - compatible : "marvell,mv64360-gpp"
+     - reg : Offset and length of the register set for this device
+
+   Example Discovery GPP node:
+     gpp@f000 {
+            compatible = "marvell,mv64360-gpp";
+            reg = <0xf100 0x20>;
+     };
+
+
+   o) Marvell Discovery PCI host bridge node
+
+   Represents the Discovery's PCI host bridge device.  The properties
+   for this node conform to Rev 2.1 of the PCI Bus Binding to IEEE
+   1275-1994.  A typical value for the compatible property is
+   "marvell,mv64360-pci".
+
+   Example Discovery PCI host bridge node
+     pci@80000000 {
+            #address-cells = <3>;
+            #size-cells = <2>;
+            #interrupt-cells = <1>;
+            device_type = "pci";
+            compatible = "marvell,mv64360-pci";
+            reg = <0xcf8 0x8>;
+            ranges = <0x01000000 0x0        0x0
+                            0x88000000 0x0 0x01000000
+                      0x02000000 0x0 0x80000000
+                            0x80000000 0x0 0x08000000>;
+            bus-range = <0 255>;
+            clock-frequency = <66000000>;
+            interrupt-parent = <&PIC>;
+            interrupt-map-mask = <0xf800 0x0 0x0 0x7>;
+            interrupt-map = <
+                    /* IDSEL 0x0a */
+                    0x5000 0 0 1 &PIC 80
+                    0x5000 0 0 2 &PIC 81
+                    0x5000 0 0 3 &PIC 91
+                    0x5000 0 0 4 &PIC 93
+
+                    /* IDSEL 0x0b */
+                    0x5800 0 0 1 &PIC 91
+                    0x5800 0 0 2 &PIC 93
+                    0x5800 0 0 3 &PIC 80
+                    0x5800 0 0 4 &PIC 81
+
+                    /* IDSEL 0x0c */
+                    0x6000 0 0 1 &PIC 91
+                    0x6000 0 0 2 &PIC 93
+                    0x6000 0 0 3 &PIC 80
+                    0x6000 0 0 4 &PIC 81
+
+                    /* IDSEL 0x0d */
+                    0x6800 0 0 1 &PIC 93
+                    0x6800 0 0 2 &PIC 80
+                    0x6800 0 0 3 &PIC 81
+                    0x6800 0 0 4 &PIC 91
+            >;
+     };
+
+
+   p) Marvell Discovery CPU Error nodes
+
+   Represent the Discovery's CPU error handler device.
+
+   Required properties:
+     - compatible : "marvell,mv64360-cpu-error"
+     - reg : Offset and length of the register set for this device
+     - interrupts : the interrupt number for this device
+     - interrupt-parent : the phandle for the interrupt controller
+       that services interrupts for this device.
+
+   Example Discovery CPU Error node:
+     cpu-error@0070 {
+            compatible = "marvell,mv64360-cpu-error";
+            reg = <0x70 0x10 0x128 0x28>;
+            interrupts = <3>;
+            interrupt-parent = <&PIC>;
+     };
+
+
+   q) Marvell Discovery SRAM Controller nodes
+
+   Represent the Discovery's SRAM controller device.
+
+   Required properties:
+     - compatible : "marvell,mv64360-sram-ctrl"
+     - reg : Offset and length of the register set for this device
+     - interrupts : the interrupt number for this device
+     - interrupt-parent : the phandle for the interrupt controller
+       that services interrupts for this device.
+
+   Example Discovery SRAM Controller node:
+     sram-ctrl@0380 {
+            compatible = "marvell,mv64360-sram-ctrl";
+            reg = <0x380 0x80>;
+            interrupts = <13>;
+            interrupt-parent = <&PIC>;
+     };
+
+
+   r) Marvell Discovery PCI Error Handler nodes
+
+   Represent the Discovery's PCI error handler device.
+
+   Required properties:
+     - compatible : "marvell,mv64360-pci-error"
+     - reg : Offset and length of the register set for this device
+     - interrupts : the interrupt number for this device
+     - interrupt-parent : the phandle for the interrupt controller
+       that services interrupts for this device.
+
+   Example Discovery PCI Error Handler node:
+     pci-error@1d40 {
+            compatible = "marvell,mv64360-pci-error";
+            reg = <0x1d40 0x40 0xc28 0x4>;
+            interrupts = <12>;
+            interrupt-parent = <&PIC>;
+     };
+
+
+   s) Marvell Discovery Memory Controller nodes
+
+   Represent the Discovery's memory controller device.
+
+   Required properties:
+     - compatible : "marvell,mv64360-mem-ctrl"
+     - reg : Offset and length of the register set for this device
+     - interrupts : the interrupt number for this device
+     - interrupt-parent : the phandle for the interrupt controller
+       that services interrupts for this device.
+
+   Example Discovery Memory Controller node:
+     mem-ctrl@1400 {
+            compatible = "marvell,mv64360-mem-ctrl";
+            reg = <0x1400 0x60>;
+            interrupts = <17>;
+            interrupt-parent = <&PIC>;
+     };
+
+
diff --git a/Documentation/powerpc/dts-bindings/phy.txt b/Documentation/powerpc/dts-bindings/phy.txt
new file mode 100644 (file)
index 0000000..bb8c742
--- /dev/null
@@ -0,0 +1,25 @@
+PHY nodes
+
+Required properties:
+
+ - device_type : Should be "ethernet-phy"
+ - interrupts : <a b> where a is the interrupt number and b is a
+   field that represents an encoding of the sense and level
+   information for the interrupt.  This should be encoded based on
+   the information in section 2) depending on the type of interrupt
+   controller you have.
+ - interrupt-parent : the phandle for the interrupt controller that
+   services interrupts for this device.
+ - reg : The ID number for the phy, usually a small integer
+ - linux,phandle :  phandle for this node; likely referenced by an
+   ethernet controller node.
+
+Example:
+
+ethernet-phy@0 {
+       linux,phandle = <2452000>
+       interrupt-parent = <40000>;
+       interrupts = <35 1>;
+       reg = <0>;
+       device_type = "ethernet-phy";
+};
diff --git a/Documentation/powerpc/dts-bindings/spi-bus.txt b/Documentation/powerpc/dts-bindings/spi-bus.txt
new file mode 100644 (file)
index 0000000..e782add
--- /dev/null
@@ -0,0 +1,57 @@
+SPI (Serial Peripheral Interface) busses
+
+SPI busses can be described with a node for the SPI master device
+and a set of child nodes for each SPI slave on the bus.  For this
+discussion, it is assumed that the system's SPI controller is in
+SPI master mode.  This binding does not describe SPI controllers
+in slave mode.
+
+The SPI master node requires the following properties:
+- #address-cells  - number of cells required to define a chip select
+               address on the SPI bus.
+- #size-cells     - should be zero.
+- compatible      - name of SPI bus controller following generic names
+               recommended practice.
+No other properties are required in the SPI bus node.  It is assumed
+that a driver for an SPI bus device will understand that it is an SPI bus.
+However, the binding does not attempt to define the specific method for
+assigning chip select numbers.  Since SPI chip select configuration is
+flexible and non-standardized, it is left out of this binding with the
+assumption that board specific platform code will be used to manage
+chip selects.  Individual drivers can define additional properties to
+support describing the chip select layout.
+
+SPI slave nodes must be children of the SPI master node and can
+contain the following properties.
+- reg             - (required) chip select address of device.
+- compatible      - (required) name of SPI device following generic names
+               recommended practice
+- spi-max-frequency - (required) Maximum SPI clocking speed of device in Hz
+- spi-cpol        - (optional) Empty property indicating device requires
+               inverse clock polarity (CPOL) mode
+- spi-cpha        - (optional) Empty property indicating device requires
+               shifted clock phase (CPHA) mode
+- spi-cs-high     - (optional) Empty property indicating device requires
+               chip select active high
+
+SPI example for an MPC5200 SPI bus:
+       spi@f00 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               compatible = "fsl,mpc5200b-spi","fsl,mpc5200-spi";
+               reg = <0xf00 0x20>;
+               interrupts = <2 13 0 2 14 0>;
+               interrupt-parent = <&mpc5200_pic>;
+
+               ethernet-switch@0 {
+                       compatible = "micrel,ks8995m";
+                       spi-max-frequency = <1000000>;
+                       reg = <0>;
+               };
+
+               codec@1 {
+                       compatible = "ti,tlv320aic26";
+                       spi-max-frequency = <100000>;
+                       reg = <1>;
+               };
+       };
diff --git a/Documentation/powerpc/dts-bindings/usb-ehci.txt b/Documentation/powerpc/dts-bindings/usb-ehci.txt
new file mode 100644 (file)
index 0000000..fa18612
--- /dev/null
@@ -0,0 +1,25 @@
+USB EHCI controllers
+
+Required properties:
+  - compatible : should be "usb-ehci".
+  - reg : should contain at least address and length of the standard EHCI
+    register set for the device. Optional platform-dependent registers
+    (debug-port or other) can be also specified here, but only after
+    definition of standard EHCI registers.
+  - interrupts : one EHCI interrupt should be described here.
+If device registers are implemented in big endian mode, the device
+node should have "big-endian-regs" property.
+If controller implementation operates with big endian descriptors,
+"big-endian-desc" property should be specified.
+If both big endian registers and descriptors are used by the controller
+implementation, "big-endian" property can be specified instead of having
+both "big-endian-regs" and "big-endian-desc".
+
+Example (Sequoia 440EPx):
+    ehci@e0000300 {
+          compatible = "ibm,usb-ehci-440epx", "usb-ehci";
+          interrupt-parent = <&UIC0>;
+          interrupts = <1a 4>;
+          reg = <0 e0000300 90 0 e0000390 70>;
+          big-endian;
+   };
diff --git a/Documentation/powerpc/dts-bindings/xilinx.txt b/Documentation/powerpc/dts-bindings/xilinx.txt
new file mode 100644 (file)
index 0000000..80339fe
--- /dev/null
@@ -0,0 +1,295 @@
+   d) Xilinx IP cores
+
+   The Xilinx EDK toolchain ships with a set of IP cores (devices) for use
+   in Xilinx Spartan and Virtex FPGAs.  The devices cover the whole range
+   of standard device types (network, serial, etc.) and miscellaneous
+   devices (gpio, LCD, spi, etc).  Also, since these devices are
+   implemented within the fpga fabric every instance of the device can be
+   synthesised with different options that change the behaviour.
+
+   Each IP-core has a set of parameters which the FPGA designer can use to
+   control how the core is synthesized.  Historically, the EDK tool would
+   extract the device parameters relevant to device drivers and copy them
+   into an 'xparameters.h' in the form of #define symbols.  This tells the
+   device drivers how the IP cores are configured, but it requres the kernel
+   to be recompiled every time the FPGA bitstream is resynthesized.
+
+   The new approach is to export the parameters into the device tree and
+   generate a new device tree each time the FPGA bitstream changes.  The
+   parameters which used to be exported as #defines will now become
+   properties of the device node.  In general, device nodes for IP-cores
+   will take the following form:
+
+       (name): (generic-name)@(base-address) {
+               compatible = "xlnx,(ip-core-name)-(HW_VER)"
+                            [, (list of compatible devices), ...];
+               reg = <(baseaddr) (size)>;
+               interrupt-parent = <&interrupt-controller-phandle>;
+               interrupts = < ... >;
+               xlnx,(parameter1) = "(string-value)";
+               xlnx,(parameter2) = <(int-value)>;
+       };
+
+       (generic-name):   an open firmware-style name that describes the
+                       generic class of device.  Preferably, this is one word, such
+                       as 'serial' or 'ethernet'.
+       (ip-core-name): the name of the ip block (given after the BEGIN
+                       directive in system.mhs).  Should be in lowercase
+                       and all underscores '_' converted to dashes '-'.
+       (name):         is derived from the "PARAMETER INSTANCE" value.
+       (parameter#):   C_* parameters from system.mhs.  The C_ prefix is
+                       dropped from the parameter name, the name is converted
+                       to lowercase and all underscore '_' characters are
+                       converted to dashes '-'.
+       (baseaddr):     the baseaddr parameter value (often named C_BASEADDR).
+       (HW_VER):       from the HW_VER parameter.
+       (size):         the address range size (often C_HIGHADDR - C_BASEADDR + 1).
+
+   Typically, the compatible list will include the exact IP core version
+   followed by an older IP core version which implements the same
+   interface or any other device with the same interface.
+
+   'reg', 'interrupt-parent' and 'interrupts' are all optional properties.
+
+   For example, the following block from system.mhs:
+
+       BEGIN opb_uartlite
+               PARAMETER INSTANCE = opb_uartlite_0
+               PARAMETER HW_VER = 1.00.b
+               PARAMETER C_BAUDRATE = 115200
+               PARAMETER C_DATA_BITS = 8
+               PARAMETER C_ODD_PARITY = 0
+               PARAMETER C_USE_PARITY = 0
+               PARAMETER C_CLK_FREQ = 50000000
+               PARAMETER C_BASEADDR = 0xEC100000
+               PARAMETER C_HIGHADDR = 0xEC10FFFF
+               BUS_INTERFACE SOPB = opb_7
+               PORT OPB_Clk = CLK_50MHz
+               PORT Interrupt = opb_uartlite_0_Interrupt
+               PORT RX = opb_uartlite_0_RX
+               PORT TX = opb_uartlite_0_TX
+               PORT OPB_Rst = sys_bus_reset_0
+       END
+
+   becomes the following device tree node:
+
+       opb_uartlite_0: serial@ec100000 {
+               device_type = "serial";
+               compatible = "xlnx,opb-uartlite-1.00.b";
+               reg = <ec100000 10000>;
+               interrupt-parent = <&opb_intc_0>;
+               interrupts = <1 0>; // got this from the opb_intc parameters
+               current-speed = <d#115200>;     // standard serial device prop
+               clock-frequency = <d#50000000>; // standard serial device prop
+               xlnx,data-bits = <8>;
+               xlnx,odd-parity = <0>;
+               xlnx,use-parity = <0>;
+       };
+
+   Some IP cores actually implement 2 or more logical devices.  In
+   this case, the device should still describe the whole IP core with
+   a single node and add a child node for each logical device.  The
+   ranges property can be used to translate from parent IP-core to the
+   registers of each device.  In addition, the parent node should be
+   compatible with the bus type 'xlnx,compound', and should contain
+   #address-cells and #size-cells, as with any other bus.  (Note: this
+   makes the assumption that both logical devices have the same bus
+   binding.  If this is not true, then separate nodes should be used
+   for each logical device).  The 'cell-index' property can be used to
+   enumerate logical devices within an IP core.  For example, the
+   following is the system.mhs entry for the dual ps2 controller found
+   on the ml403 reference design.
+
+       BEGIN opb_ps2_dual_ref
+               PARAMETER INSTANCE = opb_ps2_dual_ref_0
+               PARAMETER HW_VER = 1.00.a
+               PARAMETER C_BASEADDR = 0xA9000000
+               PARAMETER C_HIGHADDR = 0xA9001FFF
+               BUS_INTERFACE SOPB = opb_v20_0
+               PORT Sys_Intr1 = ps2_1_intr
+               PORT Sys_Intr2 = ps2_2_intr
+               PORT Clkin1 = ps2_clk_rx_1
+               PORT Clkin2 = ps2_clk_rx_2
+               PORT Clkpd1 = ps2_clk_tx_1
+               PORT Clkpd2 = ps2_clk_tx_2
+               PORT Rx1 = ps2_d_rx_1
+               PORT Rx2 = ps2_d_rx_2
+               PORT Txpd1 = ps2_d_tx_1
+               PORT Txpd2 = ps2_d_tx_2
+       END
+
+   It would result in the following device tree nodes:
+
+       opb_ps2_dual_ref_0: opb-ps2-dual-ref@a9000000 {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               compatible = "xlnx,compound";
+               ranges = <0 a9000000 2000>;
+               // If this device had extra parameters, then they would
+               // go here.
+               ps2@0 {
+                       compatible = "xlnx,opb-ps2-dual-ref-1.00.a";
+                       reg = <0 40>;
+                       interrupt-parent = <&opb_intc_0>;
+                       interrupts = <3 0>;
+                       cell-index = <0>;
+               };
+               ps2@1000 {
+                       compatible = "xlnx,opb-ps2-dual-ref-1.00.a";
+                       reg = <1000 40>;
+                       interrupt-parent = <&opb_intc_0>;
+                       interrupts = <3 0>;
+                       cell-index = <0>;
+               };
+       };
+
+   Also, the system.mhs file defines bus attachments from the processor
+   to the devices.  The device tree structure should reflect the bus
+   attachments.  Again an example; this system.mhs fragment:
+
+       BEGIN ppc405_virtex4
+               PARAMETER INSTANCE = ppc405_0
+               PARAMETER HW_VER = 1.01.a
+               BUS_INTERFACE DPLB = plb_v34_0
+               BUS_INTERFACE IPLB = plb_v34_0
+       END
+
+       BEGIN opb_intc
+               PARAMETER INSTANCE = opb_intc_0
+               PARAMETER HW_VER = 1.00.c
+               PARAMETER C_BASEADDR = 0xD1000FC0
+               PARAMETER C_HIGHADDR = 0xD1000FDF
+               BUS_INTERFACE SOPB = opb_v20_0
+       END
+
+       BEGIN opb_uart16550
+               PARAMETER INSTANCE = opb_uart16550_0
+               PARAMETER HW_VER = 1.00.d
+               PARAMETER C_BASEADDR = 0xa0000000
+               PARAMETER C_HIGHADDR = 0xa0001FFF
+               BUS_INTERFACE SOPB = opb_v20_0
+       END
+
+       BEGIN plb_v34
+               PARAMETER INSTANCE = plb_v34_0
+               PARAMETER HW_VER = 1.02.a
+       END
+
+       BEGIN plb_bram_if_cntlr
+               PARAMETER INSTANCE = plb_bram_if_cntlr_0
+               PARAMETER HW_VER = 1.00.b
+               PARAMETER C_BASEADDR = 0xFFFF0000
+               PARAMETER C_HIGHADDR = 0xFFFFFFFF
+               BUS_INTERFACE SPLB = plb_v34_0
+       END
+
+       BEGIN plb2opb_bridge
+               PARAMETER INSTANCE = plb2opb_bridge_0
+               PARAMETER HW_VER = 1.01.a
+               PARAMETER C_RNG0_BASEADDR = 0x20000000
+               PARAMETER C_RNG0_HIGHADDR = 0x3FFFFFFF
+               PARAMETER C_RNG1_BASEADDR = 0x60000000
+               PARAMETER C_RNG1_HIGHADDR = 0x7FFFFFFF
+               PARAMETER C_RNG2_BASEADDR = 0x80000000
+               PARAMETER C_RNG2_HIGHADDR = 0xBFFFFFFF
+               PARAMETER C_RNG3_BASEADDR = 0xC0000000
+               PARAMETER C_RNG3_HIGHADDR = 0xDFFFFFFF
+               BUS_INTERFACE SPLB = plb_v34_0
+               BUS_INTERFACE MOPB = opb_v20_0
+       END
+
+   Gives this device tree (some properties removed for clarity):
+
+       plb@0 {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               compatible = "xlnx,plb-v34-1.02.a";
+               device_type = "ibm,plb";
+               ranges; // 1:1 translation
+
+               plb_bram_if_cntrl_0: bram@ffff0000 {
+                       reg = <ffff0000 10000>;
+               }
+
+               opb@20000000 {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges = <20000000 20000000 20000000
+                                 60000000 60000000 20000000
+                                 80000000 80000000 40000000
+                                 c0000000 c0000000 20000000>;
+
+                       opb_uart16550_0: serial@a0000000 {
+                               reg = <a00000000 2000>;
+                       };
+
+                       opb_intc_0: interrupt-controller@d1000fc0 {
+                               reg = <d1000fc0 20>;
+                       };
+               };
+       };
+
+   That covers the general approach to binding xilinx IP cores into the
+   device tree.  The following are bindings for specific devices:
+
+      i) Xilinx ML300 Framebuffer
+
+      Simple framebuffer device from the ML300 reference design (also on the
+      ML403 reference design as well as others).
+
+      Optional properties:
+       - resolution = <xres yres> : pixel resolution of framebuffer.  Some
+                                    implementations use a different resolution.
+                                    Default is <d#640 d#480>
+       - virt-resolution = <xvirt yvirt> : Size of framebuffer in memory.
+                                           Default is <d#1024 d#480>.
+       - rotate-display (empty) : rotate display 180 degrees.
+
+      ii) Xilinx SystemACE
+
+      The Xilinx SystemACE device is used to program FPGAs from an FPGA
+      bitstream stored on a CF card.  It can also be used as a generic CF
+      interface device.
+
+      Optional properties:
+       - 8-bit (empty) : Set this property for SystemACE in 8 bit mode
+
+      iii) Xilinx EMAC and Xilinx TEMAC
+
+      Xilinx Ethernet devices.  In addition to general xilinx properties
+      listed above, nodes for these devices should include a phy-handle
+      property, and may include other common network device properties
+      like local-mac-address.
+
+      iv) Xilinx Uartlite
+
+      Xilinx uartlite devices are simple fixed speed serial ports.
+
+      Required properties:
+       - current-speed : Baud rate of uartlite
+
+      v) Xilinx hwicap
+
+               Xilinx hwicap devices provide access to the configuration logic
+               of the FPGA through the Internal Configuration Access Port
+               (ICAP).  The ICAP enables partial reconfiguration of the FPGA,
+               readback of the configuration information, and some control over
+               'warm boots' of the FPGA fabric.
+
+               Required properties:
+               - xlnx,family : The family of the FPGA, necessary since the
+                      capabilities of the underlying ICAP hardware
+                      differ between different families.  May be
+                      'virtex2p', 'virtex4', or 'virtex5'.
+
+      vi) Xilinx Uart 16550
+
+      Xilinx UART 16550 devices are very similar to the NS16550 but with
+      different register spacing and an offset from the base address.
+
+      Required properties:
+       - clock-frequency : Frequency of the clock input
+       - reg-offset : A value of 3 is required
+       - reg-shift : A value of 2 is required
+
+
index 0d8d235..939a3dd 100644 (file)
@@ -240,6 +240,7 @@ AD1986A
   laptop-automute 2-channel with EAPD and HP-automute (Lenovo N100)
   ultra                2-channel with EAPD (Samsung Ultra tablet PC)
   samsung      2-channel with EAPD (Samsung R65)
+  samsung-p50  2-channel with HP-automute (Samsung P50)
 
 AD1988/AD1988B/AD1989A/AD1989B
 ==============================
index cf0e3ce..c1a5aad 100644 (file)
@@ -99,11 +99,13 @@ void parse_opts(int argc, char *argv[])
                        { "lsb",     0, 0, 'L' },
                        { "cs-high", 0, 0, 'C' },
                        { "3wire",   0, 0, '3' },
+                       { "no-cs",   0, 0, 'N' },
+                       { "ready",   0, 0, 'R' },
                        { NULL, 0, 0, 0 },
                };
                int c;
 
-               c = getopt_long(argc, argv, "D:s:d:b:lHOLC3", lopts, NULL);
+               c = getopt_long(argc, argv, "D:s:d:b:lHOLC3NR", lopts, NULL);
 
                if (c == -1)
                        break;
@@ -139,6 +141,12 @@ void parse_opts(int argc, char *argv[])
                case '3':
                        mode |= SPI_3WIRE;
                        break;
+               case 'N':
+                       mode |= SPI_NO_CS;
+                       break;
+               case 'R':
+                       mode |= SPI_READY;
+                       break;
                default:
                        print_usage(argv[0]);
                        break;
index 88e8c00..d119ba9 100644 (file)
@@ -867,12 +867,22 @@ M:        alex@shark-linux.de
 W:     http://www.shark-linux.de/shark.html
 S:     Maintained
 
+ARM/SAMSUNG ARM ARCHITECTURES
+P:     Ben Dooks
+M:     ben-linux@fluff.org
+L:     linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
+W:     http://www.fluff.org/ben/linux/
+S:     Maintained
+F:     arch/arm/plat-s3c/
+F:     arch/arm/plat-s3c24xx/
+
 ARM/S3C2410 ARM ARCHITECTURE
 P:     Ben Dooks
 M:     ben-linux@fluff.org
 L:     linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
 W:     http://www.fluff.org/ben/linux/
 S:     Maintained
+F:     arch/arm/mach-s3c2410/
 
 ARM/S3C2440 ARM ARCHITECTURE
 P:     Ben Dooks
@@ -880,6 +890,39 @@ M: ben-linux@fluff.org
 L:     linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
 W:     http://www.fluff.org/ben/linux/
 S:     Maintained
+F:     arch/arm/mach-s3c2440/
+
+ARM/S3C2442 ARM ARCHITECTURE
+P:     Ben Dooks
+M:     ben-linux@fluff.org
+L:     linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
+W:     http://www.fluff.org/ben/linux/
+S:     Maintained
+F:     arch/arm/mach-s3c2442/
+
+ARM/S3C2443 ARM ARCHITECTURE
+P:     Ben Dooks
+M:     ben-linux@fluff.org
+L:     linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
+W:     http://www.fluff.org/ben/linux/
+S:     Maintained
+F:     arch/arm/mach-s3c2443/
+
+ARM/S3C6400 ARM ARCHITECTURE
+P:     Ben Dooks
+M:     ben-linux@fluff.org
+L:     linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
+W:     http://www.fluff.org/ben/linux/
+S:     Maintained
+F:     arch/arm/mach-s3c6400/
+
+ARM/S3C6410 ARM ARCHITECTURE
+P:     Ben Dooks
+M:     ben-linux@fluff.org
+L:     linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
+W:     http://www.fluff.org/ben/linux/
+S:     Maintained
+F:     arch/arm/mach-s3c6410/
 
 ARM/TECHNOLOGIC SYSTEMS TS7250 MACHINE SUPPORT
 P:     Lennert Buytenhek
@@ -2094,9 +2137,9 @@ F:        drivers/edac/i5400_edac.c
 
 EDAC-I82975X
 P:     Ranganathan Desikan
-M:     rdesikan@jetzbroadband.com
+M:     ravi@jetztechnologies.com
 P:     Arvind R.
-M:     arvind@acarlab.com
+M:     arvind@jetztechnologies.com
 L:     bluesmoke-devel@lists.sourceforge.net (moderated for non-subscribers)
 W:     bluesmoke.sourceforge.net
 S:     Maintained
@@ -2815,7 +2858,9 @@ S:        Maintained
 
 IA64 (Itanium) PLATFORM
 P:     Tony Luck
+P:     Fenghua Yu
 M:     tony.luck@intel.com
+M:     fenghua.yu@intel.com
 L:     linux-ia64@vger.kernel.org
 W:     http://www.ia64-linux.org/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/aegl/linux-2.6.git
@@ -5541,8 +5586,8 @@ F:        drivers/staging/
 
 STARFIRE/DURALAN NETWORK DRIVER
 P:     Ion Badulescu
-M:     ionut@cs.columbia.edu
-S:     Maintained
+M:     ionut@badula.org
+S:     Odd Fixes
 F:     drivers/net/starfire*
 
 STARMODE RADIO IP (STRIP) PROTOCOL DRIVER
@@ -5675,6 +5720,13 @@ F:       drivers/misc/tifm*
 F:     drivers/mmc/host/tifm_sd.c
 F:     include/linux/tifm.h
 
+TI TWL4030 SERIES SOC CODEC DRIVER
+P:     Peter Ujfalusi
+M:     peter.ujfalusi@nokia.com
+L:     alsa-devel@alsa-project.org (moderated for non-subscribers)
+S:     Maintained
+F:     sound/soc/codecs/twl4030*
+
 TIPC NETWORK LAYER
 P:     Per Liden
 M:     per.liden@ericsson.com
index d1216fe..0aeec59 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 6
 SUBLEVEL = 31
-EXTRAVERSION = -rc1
+EXTRAVERSION = -rc2
 NAME = Man-Eating Seals of Antiquity
 
 # *DOCUMENTATION*
@@ -140,15 +140,13 @@ _all: modules
 endif
 
 srctree                := $(if $(KBUILD_SRC),$(KBUILD_SRC),$(CURDIR))
-TOPDIR         := $(srctree)
-# FIXME - TOPDIR is obsolete, use srctree/objtree
 objtree                := $(CURDIR)
 src            := $(srctree)
 obj            := $(objtree)
 
 VPATH          := $(srctree)$(if $(KBUILD_EXTMOD),:$(KBUILD_EXTMOD))
 
-export srctree objtree VPATH TOPDIR
+export srctree objtree VPATH
 
 
 # SUBARCH tells the usermode build what the underlying arch is.  That is set
@@ -344,7 +342,8 @@ KBUILD_CPPFLAGS := -D__KERNEL__
 
 KBUILD_CFLAGS   := -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs \
                   -fno-strict-aliasing -fno-common \
-                  -Werror-implicit-function-declaration
+                  -Werror-implicit-function-declaration \
+                  -Wno-format-security
 KBUILD_AFLAGS   := -D__ASSEMBLY__
 
 # Read KERNELRELEASE from include/config/kernel.release (if it exists)
index 06c5c7a..b663f1f 100644 (file)
@@ -30,7 +30,7 @@ extern unsigned long __per_cpu_offset[NR_CPUS];
 
 #ifndef MODULE
 #define SHIFT_PERCPU_PTR(var, offset) RELOC_HIDE(&per_cpu_var(var), (offset))
-#define PER_CPU_ATTRIBUTES
+#define PER_CPU_DEF_ATTRIBUTES
 #else
 /*
  * To calculate addresses of locally defined variables, GCC uses 32-bit
@@ -49,7 +49,7 @@ extern unsigned long __per_cpu_offset[NR_CPUS];
                : "=&r"(__ptr), "=&r"(tmp_gp));         \
        (typeof(&per_cpu_var(var)))(__ptr + (offset)); })
 
-#define PER_CPU_ATTRIBUTES     __used
+#define PER_CPU_DEF_ATTRIBUTES __used
 
 #endif /* MODULE */
 
@@ -71,7 +71,7 @@ extern unsigned long __per_cpu_offset[NR_CPUS];
 #define __get_cpu_var(var)             per_cpu_var(var)
 #define __raw_get_cpu_var(var)         per_cpu_var(var)
 
-#define PER_CPU_ATTRIBUTES
+#define PER_CPU_DEF_ATTRIBUTES
 
 #endif /* SMP */
 
index a71fd94..a89e473 100644 (file)
@@ -99,14 +99,6 @@ config DEBUG_CLPS711X_UART2
          output to the second serial port on these devices.  Saying N will
          cause the debug messages to appear on the first serial port.
 
-config DEBUG_S3C_PORT
-       depends on DEBUG_LL && PLAT_S3C
-       bool "Kernel low-level debugging messages via S3C UART"
-       help
-         Say Y here if you want debug print routines to go to one of the
-         S3C internal UARTs. The chosen UART must have been configured
-         before it is used.
-
 config DEBUG_S3C_UART
        depends on PLAT_S3C
        int "S3C UART to use for low-level debug"
index 2d58b8f..b498104 100644 (file)
@@ -260,6 +260,7 @@ CONFIG_MACH_NEXCODER_2440=y
 CONFIG_SMDK2440_CPU2440=y
 CONFIG_MACH_AT2440EVB=y
 CONFIG_CPU_S3C2442=y
+CONFIG_MACH_MINI2440=y
 
 #
 # S3C2442 Machines
@@ -2298,7 +2299,6 @@ CONFIG_DEBUG_ERRORS=y
 # CONFIG_DEBUG_STACK_USAGE is not set
 CONFIG_DEBUG_LL=y
 # CONFIG_DEBUG_ICEDCC is not set
-CONFIG_DEBUG_S3C_PORT=y
 CONFIG_DEBUG_S3C_UART=0
 
 #
index 2e8fa50..3286060 100644 (file)
@@ -816,7 +816,6 @@ CONFIG_DEBUG_ERRORS=y
 # CONFIG_DEBUG_STACK_USAGE is not set
 CONFIG_DEBUG_LL=y
 # CONFIG_DEBUG_ICEDCC is not set
-CONFIG_DEBUG_S3C_PORT=y
 CONFIG_DEBUG_S3C_UART=0
 
 #
index 07dfb98..9d32fae 100644 (file)
@@ -857,7 +857,6 @@ CONFIG_DEBUG_ERRORS=y
 # CONFIG_DEBUG_STACK_USAGE is not set
 CONFIG_DEBUG_LL=y
 # CONFIG_DEBUG_ICEDCC is not set
-# CONFIG_DEBUG_S3C_PORT is not set
 CONFIG_DEBUG_S3C_UART=0
 
 #
index be962c1..9c746af 100644 (file)
@@ -12,7 +12,7 @@
 
 /* PAGE_SHIFT determines the page size */
 #define PAGE_SHIFT             12
-#define PAGE_SIZE              (1UL << PAGE_SHIFT)
+#define PAGE_SIZE              (_AC(1,UL) << PAGE_SHIFT)
 #define PAGE_MASK              (~(PAGE_SIZE-1))
 
 #ifndef __ASSEMBLY__
index 096f600..b7c3490 100644 (file)
@@ -98,17 +98,6 @@ unlock:
        return 0;
 }
 
-/* Handle bad interrupts */
-static struct irq_desc bad_irq_desc = {
-       .handle_irq = handle_bad_irq,
-       .lock = __SPIN_LOCK_UNLOCKED(bad_irq_desc.lock),
-};
-
-#ifdef CONFIG_CPUMASK_OFFSTACK
-/* We are not allocating bad_irq_desc.affinity or .pending_mask */
-#error "ARM architecture does not support CONFIG_CPUMASK_OFFSTACK."
-#endif
-
 /*
  * do_IRQ handles all hardware IRQ's.  Decoded IRQs should not
  * come via this function.  Instead, they should provide their
@@ -124,10 +113,13 @@ asmlinkage void __exception asm_do_IRQ(unsigned int irq, struct pt_regs *regs)
         * Some hardware gives randomly wrong interrupts.  Rather
         * than crashing, do something sensible.
         */
-       if (irq >= NR_IRQS)
-               handle_bad_irq(irq, &bad_irq_desc);
-       else
+       if (unlikely(irq >= NR_IRQS)) {
+               if (printk_ratelimit())
+                       printk(KERN_WARNING "Bad IRQ%u\n", irq);
+               ack_bad_irq(irq);
+       } else {
                generic_handle_irq(irq);
+       }
 
        /* AT91 specific workaround */
        irq_finish(irq);
@@ -165,10 +157,6 @@ void __init init_IRQ(void)
        for (irq = 0; irq < NR_IRQS; irq++)
                irq_desc[irq].status |= IRQ_NOREQUEST | IRQ_NOPROBE;
 
-#ifdef CONFIG_SMP
-       cpumask_setall(bad_irq_desc.affinity);
-       bad_irq_desc.node = smp_processor_id();
-#endif
        init_arch_irq();
 }
 
index 4340bf3..6937102 100644 (file)
@@ -6,6 +6,7 @@
 #include <asm-generic/vmlinux.lds.h>
 #include <asm/thread_info.h>
 #include <asm/memory.h>
+#include <asm/page.h>
        
 OUTPUT_ARCH(arm)
 ENTRY(stext)
@@ -63,7 +64,7 @@ SECTIONS
                        usr/built-in.o(.init.ramfs)
                __initramfs_end = .;
 #endif
-               . = ALIGN(4096);
+               . = ALIGN(PAGE_SIZE);
                __per_cpu_load = .;
                __per_cpu_start = .;
                        *(.data.percpu.page_aligned)
@@ -73,7 +74,7 @@ SECTIONS
 #ifndef CONFIG_XIP_KERNEL
                __init_begin = _stext;
                INIT_DATA
-               . = ALIGN(4096);
+               . = ALIGN(PAGE_SIZE);
                __init_end = .;
 #endif
        }
@@ -118,7 +119,7 @@ SECTIONS
                *(.got)                 /* Global offset table          */
        }
 
-       RODATA
+       RO_DATA(PAGE_SIZE)
 
        _etext = .;                     /* End of text and rodata section */
 
@@ -158,17 +159,17 @@ SECTIONS
                *(.data.init_task)
 
 #ifdef CONFIG_XIP_KERNEL
-               . = ALIGN(4096);
+               . = ALIGN(PAGE_SIZE);
                __init_begin = .;
                INIT_DATA
-               . = ALIGN(4096);
+               . = ALIGN(PAGE_SIZE);
                __init_end = .;
 #endif
 
-               . = ALIGN(4096);
+               . = ALIGN(PAGE_SIZE);
                __nosave_begin = .;
                *(.data.nosave)
-               . = ALIGN(4096);
+               . = ALIGN(PAGE_SIZE);
                __nosave_end = .;
 
                /*
index cc270be..a55398e 100644 (file)
@@ -24,6 +24,8 @@
 #include <linux/platform_device.h>
 #include <linux/spi/spi.h>
 #include <linux/spi/at73c213.h>
+#include <linux/gpio_keys.h>
+#include <linux/input.h>
 #include <linux/clk.h>
 
 #include <mach/hardware.h>
@@ -218,6 +220,56 @@ static struct gpio_led ek_leds[] = {
        }
 };
 
+
+/*
+ * GPIO Buttons
+ */
+#if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
+static struct gpio_keys_button ek_buttons[] = {
+       {
+               .gpio           = AT91_PIN_PA30,
+               .code           = BTN_3,
+               .desc           = "Button 3",
+               .active_low     = 1,
+               .wakeup         = 1,
+       },
+       {
+               .gpio           = AT91_PIN_PA31,
+               .code           = BTN_4,
+               .desc           = "Button 4",
+               .active_low     = 1,
+               .wakeup         = 1,
+       }
+};
+
+static struct gpio_keys_platform_data ek_button_data = {
+       .buttons        = ek_buttons,
+       .nbuttons       = ARRAY_SIZE(ek_buttons),
+};
+
+static struct platform_device ek_button_device = {
+       .name           = "gpio-keys",
+       .id             = -1,
+       .num_resources  = 0,
+       .dev            = {
+               .platform_data  = &ek_button_data,
+       }
+};
+
+static void __init ek_add_device_buttons(void)
+{
+       at91_set_gpio_input(AT91_PIN_PA30, 1);  /* btn3 */
+       at91_set_deglitch(AT91_PIN_PA30, 1);
+       at91_set_gpio_input(AT91_PIN_PA31, 1);  /* btn4 */
+       at91_set_deglitch(AT91_PIN_PA31, 1);
+
+       platform_device_register(&ek_button_device);
+}
+#else
+static void __init ek_add_device_buttons(void) {}
+#endif
+
+
 static struct i2c_board_info __initdata ek_i2c_devices[] = {
        {
                I2C_BOARD_INFO("24c512", 0x50),
@@ -245,6 +297,8 @@ static void __init ek_board_init(void)
        at91_add_device_i2c(ek_i2c_devices, ARRAY_SIZE(ek_i2c_devices));
        /* LEDs */
        at91_gpio_leds(ek_leds, ARRAY_SIZE(ek_leds));
+       /* Push Buttons */
+       ek_add_device_buttons();
        /* PCK0 provides MCLK to the WM8731 */
        at91_set_B_periph(AT91_PIN_PC1, 0);
        /* SSC (for WM8731) */
index 35e12a4..f6b5672 100644 (file)
@@ -186,19 +186,21 @@ static struct fb_monspecs at91fb_default_monspecs = {
 static void at91_lcdc_power_control(int on)
 {
        if (on)
-               at91_set_gpio_value(AT91_PIN_PA30, 0);  /* power up */
+               at91_set_gpio_value(AT91_PIN_PC1, 0);   /* power up */
        else
-               at91_set_gpio_value(AT91_PIN_PA30, 1);  /* power down */
+               at91_set_gpio_value(AT91_PIN_PC1, 1);   /* power down */
 }
 
 /* Driver datas */
 static struct atmel_lcdfb_info __initdata ek_lcdc_data = {
+       .lcdcon_is_backlight            = true,
        .default_bpp                    = 16,
        .default_dmacon                 = ATMEL_LCDC_DMAEN,
        .default_lcdcon2                = AT91SAM9RL_DEFAULT_LCDCON2,
        .default_monspecs               = &at91fb_default_monspecs,
        .atmel_lcdfb_power_control      = at91_lcdc_power_control,
        .guard_time                     = 1,
+       .lcd_wiring_mode                = ATMEL_LCDC_WIRING_RGB,
 };
 
 #else
index e70fc7c..ed2a48a 100644 (file)
@@ -36,7 +36,6 @@
 #include <mach/hwa742.h>
 #include <mach/lcd_mipid.h>
 #include <mach/mmc.h>
-#include <mach/usb.h>
 #include <mach/clock.h>
 
 #define ADS7846_PENDOWN_GPIO   15
@@ -205,9 +204,11 @@ static int nokia770_mmc_get_cover_state(struct device *dev, int slot)
 static struct omap_mmc_platform_data nokia770_mmc2_data = {
        .nr_slots                       = 1,
        .dma_mask                       = 0xffffffff,
+       .max_freq                       = 12000000,
        .slots[0]       = {
                .set_power              = nokia770_mmc_set_power,
                .get_cover_state        = nokia770_mmc_get_cover_state,
+               .ocr_mask               = MMC_VDD_32_33|MMC_VDD_33_34,
                .name                   = "mmcblk",
        },
 };
index 0af4d6c..6810b4a 100644 (file)
@@ -203,5 +203,5 @@ module_exit(omap1_mbox_exit);
 
 MODULE_LICENSE("GPL v2");
 MODULE_DESCRIPTION("omap mailbox: omap1 architecture specific functions");
-MODULE_AUTHOR("Hiroshi DOYU" <Hiroshi.DOYU@nokia.com>);
+MODULE_AUTHOR("Hiroshi DOYU <Hiroshi.DOYU@nokia.com>");
 MODULE_ALIAS("platform:omap1-mailbox");
index da93b86..9a0bf67 100644 (file)
@@ -362,6 +362,7 @@ static struct omap_onenand_platform_data board_onenand_data = {
        .gpio_irq       = 65,
        .parts          = onenand_partitions,
        .nr_parts       = ARRAY_SIZE(onenand_partitions),
+       .flags          = ONENAND_SYNC_READWRITE,
 };
 
 static void __init board_onenand_init(void)
index 2fd22f9..54fec53 100644 (file)
@@ -31,6 +31,8 @@ static struct platform_device gpmc_onenand_device = {
 static int omap2_onenand_set_async_mode(int cs, void __iomem *onenand_base)
 {
        struct gpmc_timings t;
+       u32 reg;
+       int err;
 
        const int t_cer = 15;
        const int t_avdp = 12;
@@ -43,6 +45,11 @@ static int omap2_onenand_set_async_mode(int cs, void __iomem *onenand_base)
        const int t_wpl = 40;
        const int t_wph = 30;
 
+       /* Ensure sync read and sync write are disabled */
+       reg = readw(onenand_base + ONENAND_REG_SYS_CFG1);
+       reg &= ~ONENAND_SYS_CFG1_SYNC_READ & ~ONENAND_SYS_CFG1_SYNC_WRITE;
+       writew(reg, onenand_base + ONENAND_REG_SYS_CFG1);
+
        memset(&t, 0, sizeof(t));
        t.sync_clk = 0;
        t.cs_on = 0;
@@ -74,7 +81,16 @@ static int omap2_onenand_set_async_mode(int cs, void __iomem *onenand_base)
                          GPMC_CONFIG1_DEVICESIZE_16 |
                          GPMC_CONFIG1_MUXADDDATA);
 
-       return gpmc_cs_set_timings(cs, &t);
+       err = gpmc_cs_set_timings(cs, &t);
+       if (err)
+               return err;
+
+       /* Ensure sync read and sync write are disabled */
+       reg = readw(onenand_base + ONENAND_REG_SYS_CFG1);
+       reg &= ~ONENAND_SYS_CFG1_SYNC_READ & ~ONENAND_SYS_CFG1_SYNC_WRITE;
+       writew(reg, onenand_base + ONENAND_REG_SYS_CFG1);
+
+       return 0;
 }
 
 static void set_onenand_cfg(void __iomem *onenand_base, int latency,
@@ -124,7 +140,8 @@ static int omap2_onenand_set_sync_mode(struct omap_onenand_platform_data *cfg,
        } else if (cfg->flags & ONENAND_SYNC_READWRITE) {
                sync_read = 1;
                sync_write = 1;
-       }
+       } else
+               return omap2_onenand_set_async_mode(cs, onenand_base);
 
        if (!freq) {
                /* Very first call freq is not known */
index 458990e..a98201c 100644 (file)
@@ -48,6 +48,28 @@ int omap_chip_is(struct omap_chip_id oci)
 }
 EXPORT_SYMBOL(omap_chip_is);
 
+int omap_type(void)
+{
+       u32 val = 0;
+
+       if (cpu_is_omap24xx())
+               val = omap_ctrl_readl(OMAP24XX_CONTROL_STATUS);
+       else if (cpu_is_omap34xx())
+               val = omap_ctrl_readl(OMAP343X_CONTROL_STATUS);
+       else {
+               pr_err("Cannot detect omap type!\n");
+               goto out;
+       }
+
+       val &= OMAP2_DEVICETYPE_MASK;
+       val >>= 8;
+
+out:
+       return val;
+}
+EXPORT_SYMBOL(omap_type);
+
+
 /*----------------------------------------------------------------------------*/
 
 #define OMAP_TAP_IDCODE                0x0204
index fd5b8a5..6f71f37 100644 (file)
@@ -282,12 +282,12 @@ static int __devinit omap2_mbox_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        /* DSP or IVA2 IRQ */
-       mbox_dsp_info.irq = platform_get_irq(pdev, 0);
-       if (mbox_dsp_info.irq < 0) {
+       ret = platform_get_irq(pdev, 0);
+       if (ret < 0) {
                dev_err(&pdev->dev, "invalid irq resource\n");
-               ret = -ENODEV;
                goto err_dsp;
        }
+       mbox_dsp_info.irq = ret;
 
        ret = omap_mbox_register(&pdev->dev, &mbox_dsp_info);
        if (ret)
index 9756a87..1541fd4 100644 (file)
@@ -263,8 +263,19 @@ static int twl_mmc1_set_power(struct device *dev, int slot, int power_on,
 static int twl_mmc23_set_power(struct device *dev, int slot, int power_on, int vdd)
 {
        int ret = 0;
-       struct twl_mmc_controller *c = &hsmmc[1];
+       struct twl_mmc_controller *c = NULL;
        struct omap_mmc_platform_data *mmc = dev->platform_data;
+       int i;
+
+       for (i = 1; i < ARRAY_SIZE(hsmmc); i++) {
+               if (mmc == hsmmc[i].mmc) {
+                       c = &hsmmc[i];
+                       break;
+               }
+       }
+
+       if (c == NULL)
+               return -ENODEV;
 
        /* If we don't see a Vcc regulator, assume it's a fixed
         * voltage always-on regulator.
index 6a5bc30..ec71a69 100644 (file)
@@ -48,8 +48,6 @@
 #include <plat/mci.h>
 #include <plat/udc.h>
 
-#include <plat/regs-serial.h>
-
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/nand.h>
 #include <linux/mtd/nand_ecc.h>
@@ -275,6 +273,7 @@ static struct s3c2410_nand_set mini2440_nand_sets[] __initdata = {
                .nr_chips       = 1,
                .nr_partitions  = ARRAY_SIZE(mini2440_default_nand_part),
                .partitions     = mini2440_default_nand_part,
+               .flash_bbt      = 1, /* we use u-boot to create a BBT */
        },
 };
 
index e23b581..0fb385b 100644 (file)
@@ -433,8 +433,7 @@ static struct s3c2410_nand_set gta02_nand_sets[] = {
                 */
                .name           = "neo1973-nand",
                .nr_chips       = 1,
-               .use_bbt        = 1,
-               .force_soft_ecc = 1,
+               .flash_bbt      = 1,
        },
 };
 
index def14ec..7677a4a 100644 (file)
@@ -2457,6 +2457,19 @@ static int __init omap_init_dma(void)
                setup_irq(irq, &omap24xx_dma_irq);
        }
 
+       /* Enable smartidle idlemodes and autoidle */
+       if (cpu_is_omap34xx()) {
+               u32 v = dma_read(OCP_SYSCONFIG);
+               v &= ~(DMA_SYSCONFIG_MIDLEMODE_MASK |
+                               DMA_SYSCONFIG_SIDLEMODE_MASK |
+                               DMA_SYSCONFIG_AUTOIDLE);
+               v |= (DMA_SYSCONFIG_MIDLEMODE(DMA_IDLEMODE_SMARTIDLE) |
+                       DMA_SYSCONFIG_SIDLEMODE(DMA_IDLEMODE_SMARTIDLE) |
+                       DMA_SYSCONFIG_AUTOIDLE);
+               dma_write(v , OCP_SYSCONFIG);
+       }
+
+
        /* FIXME: Update LCD DMA to work on 24xx */
        if (cpu_class_is_omap1()) {
                r = request_irq(INT_DMA_LCD, lcd_dma_irq_handler, 0,
index 7fd89ba..26b387c 100644 (file)
@@ -1585,6 +1585,7 @@ static int __init _omap_gpio_init(void)
                        __raw_writel(0x00000000, bank->base + OMAP24XX_GPIO_IRQENABLE1);
                        __raw_writel(0xffffffff, bank->base + OMAP24XX_GPIO_IRQSTATUS1);
                        __raw_writew(0x0015, bank->base + OMAP24XX_GPIO_SYSCONFIG);
+                       __raw_writel(0x00000000, bank->base + OMAP24XX_GPIO_DEBOUNCE_EN);
 
                        /* Initialize interface clock ungated, module enabled */
                        __raw_writel(0, bank->base + OMAP24XX_GPIO_CTRL);
index fc60c4e..285eaa3 100644 (file)
 #ifndef __ASM_ARCH_OMAP_CPU_H
 #define __ASM_ARCH_OMAP_CPU_H
 
+/*
+ * Omap device type i.e. EMU/HS/TST/GP/BAD
+ */
+#define OMAP2_DEVICE_TYPE_TEST         0
+#define OMAP2_DEVICE_TYPE_EMU          1
+#define OMAP2_DEVICE_TYPE_SEC          2
+#define OMAP2_DEVICE_TYPE_GP           3
+#define OMAP2_DEVICE_TYPE_BAD          4
+
+int omap_type(void);
+
 struct omap_chip_id {
        u8 oc;
        u8 type;
@@ -424,17 +435,6 @@ IS_OMAP_TYPE(3430, 0x3430)
 
 
 int omap_chip_is(struct omap_chip_id oci);
-int omap_type(void);
-
-/*
- * Macro to detect device type i.e. EMU/HS/TST/GP/BAD
- */
-#define OMAP2_DEVICE_TYPE_TEST         0
-#define OMAP2_DEVICE_TYPE_EMU          1
-#define OMAP2_DEVICE_TYPE_SEC          2
-#define OMAP2_DEVICE_TYPE_GP           3
-#define OMAP2_DEVICE_TYPE_BAD          4
-
 void omap2_check_revision(void);
 
 #endif    /* defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) */
index 8c1eae8..7b939cc 100644 (file)
 #define DMA_THREAD_FIFO_25             (0x02 << 14)
 #define DMA_THREAD_FIFO_50             (0x03 << 14)
 
+/* DMA4_OCP_SYSCONFIG bits */
+#define DMA_SYSCONFIG_MIDLEMODE_MASK           (3 << 12)
+#define DMA_SYSCONFIG_CLOCKACTIVITY_MASK       (3 << 8)
+#define DMA_SYSCONFIG_EMUFREE                  (1 << 5)
+#define DMA_SYSCONFIG_SIDLEMODE_MASK           (3 << 3)
+#define DMA_SYSCONFIG_SOFTRESET                        (1 << 2)
+#define DMA_SYSCONFIG_AUTOIDLE                 (1 << 0)
+
+#define DMA_SYSCONFIG_MIDLEMODE(n)             ((n) << 12)
+#define DMA_SYSCONFIG_SIDLEMODE(n)             ((n) << 3)
+
+#define DMA_IDLEMODE_SMARTIDLE                 0x2
+#define DMA_IDLEMODE_NO_IDLE                   0x1
+#define DMA_IDLEMODE_FORCE_IDLE                        0x0
+
 /* Chaining modes*/
 #ifndef CONFIG_ARCH_OMAP1
 #define OMAP_DMA_STATIC_CHAIN          0x1
index 3b28147..73f483d 100644 (file)
 #define OMAP2_IO_ADDRESS(pa)   IOMEM(__OMAP2_IO_ADDRESS(pa))
 
 #ifdef __ASSEMBLER__
-#define IOMEM(x)               x
+#define IOMEM(x)               (x)
 #else
 #define IOMEM(x)               ((void __force __iomem *)(x))
 
index 4cf449f..4a03013 100644 (file)
@@ -298,7 +298,7 @@ void flush_iotlb_page(struct iommu *obj, u32 da)
                if ((start <= da) && (da < start + bytes)) {
                        dev_dbg(obj->dev, "%s: %08x<=%08x(%x)\n",
                                __func__, start, da, bytes);
-
+                       iotlb_load_cr(obj, &cr);
                        iommu_write_reg(obj, 1, MMU_FLUSH_ENTRY);
                }
        }
index 65006df..4ea7380 100644 (file)
@@ -133,7 +133,12 @@ void __init omap_detect_sram(void)
                        if (cpu_is_omap34xx()) {
                                omap_sram_base = OMAP3_SRAM_PUB_VA;
                                omap_sram_start = OMAP3_SRAM_PUB_PA;
-                               omap_sram_size = 0x8000; /* 32K */
+                               if ((omap_type() == OMAP2_DEVICE_TYPE_EMU) ||
+                                   (omap_type() == OMAP2_DEVICE_TYPE_SEC)) {
+                                       omap_sram_size = 0x7000; /* 28K */
+                               } else {
+                                       omap_sram_size = 0x8000; /* 32K */
+                               }
                        } else {
                                omap_sram_base = OMAP2_SRAM_PUB_VA;
                                omap_sram_start = OMAP2_SRAM_PUB_PA;
index 74bb7cb..0761766 100644 (file)
@@ -34,7 +34,7 @@ obj-$(CONFIG_S3C_DEV_HSMMC)   += dev-hsmmc.o
 obj-$(CONFIG_S3C_DEV_HSMMC1)   += dev-hsmmc1.o
 obj-y                          += dev-i2c0.o
 obj-$(CONFIG_S3C_DEV_I2C1)     += dev-i2c1.o
-obj-$(CONFIG_SND_S3C24XX_SOC)  += dev-audio.o
+obj-$(CONFIG_SND_S3C64XX_SOC_I2S)      += dev-audio.o
 obj-$(CONFIG_S3C_DEV_FB)       += dev-fb.o
 obj-$(CONFIG_S3C_DEV_USB_HOST) += dev-usb.o
 obj-$(CONFIG_S3C_DEV_USB_HSOTG)        += dev-usb-hsotg.o
index b5b9c4d..2e17082 100644 (file)
@@ -37,6 +37,7 @@ extern struct platform_device s3c_device_i2c1;
 extern struct platform_device s3c_device_rtc;
 extern struct platform_device s3c_device_adc;
 extern struct platform_device s3c_device_sdi;
+extern struct platform_device s3c_device_iis;
 extern struct platform_device s3c_device_hwmon;
 extern struct platform_device s3c_device_hsmmc0;
 extern struct platform_device s3c_device_hsmmc1;
index 636cb12..579a165 100644 (file)
@@ -29,7 +29,7 @@ obj-$(CONFIG_PM_SIMTEC)               += pm-simtec.o
 obj-$(CONFIG_PM)               += pm.o
 obj-$(CONFIG_PM)               += irq-pm.o
 obj-$(CONFIG_PM)               += sleep.o
-obj-$(CONFIG_HAVE_PWM)         += pwm.o
+obj-$(CONFIG_S3C24XX_PWM)      += pwm.o
 obj-$(CONFIG_S3C2410_CLOCK)    += s3c2410-clock.o
 obj-$(CONFIG_S3C2410_DMA)      += dma.o
 obj-$(CONFIG_S3C24XX_ADC)      += adc.o
index 9edf789..da7a617 100644 (file)
@@ -12,8 +12,7 @@
 */
 
 #include <linux/kernel.h>
-
-#include <mach/hardware.h>
+#include <linux/gpio.h>
 
 #include <mach/spi.h>
 #include <mach/regs-gpio.h>
index f34d0fc..86b9edc 100644 (file)
@@ -12,8 +12,7 @@
 */
 
 #include <linux/kernel.h>
-
-#include <mach/hardware.h>
+#include <linux/gpio.h>
 
 #include <mach/spi.h>
 #include <mach/regs-gpio.h>
index 8a5bd7a..b86e19c 100644 (file)
@@ -7,6 +7,7 @@ config FRV
        default y
        select HAVE_IDE
        select HAVE_ARCH_TRACEHOOK
+       select HAVE_PERF_COUNTERS
 
 config ZONE_DMA
        bool
index 0409d98..00a57af 100644 (file)
@@ -121,10 +121,72 @@ static inline void atomic_dec(atomic_t *v)
 #define atomic_dec_and_test(v)         (atomic_sub_return(1, (v)) == 0)
 #define atomic_inc_and_test(v)         (atomic_add_return(1, (v)) == 0)
 
+/*
+ * 64-bit atomic ops
+ */
+typedef struct {
+       volatile long long counter;
+} atomic64_t;
+
+#define ATOMIC64_INIT(i)       { (i) }
+
+static inline long long atomic64_read(atomic64_t *v)
+{
+       long long counter;
+
+       asm("ldd%I1 %M1,%0"
+           : "=e"(counter)
+           : "m"(v->counter));
+       return counter;
+}
+
+static inline void atomic64_set(atomic64_t *v, long long i)
+{
+       asm volatile("std%I0 %1,%M0"
+                    : "=m"(v->counter)
+                    : "e"(i));
+}
+
+extern long long atomic64_inc_return(atomic64_t *v);
+extern long long atomic64_dec_return(atomic64_t *v);
+extern long long atomic64_add_return(long long i, atomic64_t *v);
+extern long long atomic64_sub_return(long long i, atomic64_t *v);
+
+static inline long long atomic64_add_negative(long long i, atomic64_t *v)
+{
+       return atomic64_add_return(i, v) < 0;
+}
+
+static inline void atomic64_add(long long i, atomic64_t *v)
+{
+       atomic64_add_return(i, v);
+}
+
+static inline void atomic64_sub(long long i, atomic64_t *v)
+{
+       atomic64_sub_return(i, v);
+}
+
+static inline void atomic64_inc(atomic64_t *v)
+{
+       atomic64_inc_return(v);
+}
+
+static inline void atomic64_dec(atomic64_t *v)
+{
+       atomic64_dec_return(v);
+}
+
+#define atomic64_sub_and_test(i,v)     (atomic64_sub_return((i), (v)) == 0)
+#define atomic64_dec_and_test(v)       (atomic64_dec_return((v)) == 0)
+#define atomic64_inc_and_test(v)       (atomic64_inc_return((v)) == 0)
+
 /*****************************************************************************/
 /*
  * exchange value with memory
  */
+extern uint64_t __xchg_64(uint64_t i, volatile void *v);
+
 #ifndef CONFIG_FRV_OUTOFLINE_ATOMIC_OPS
 
 #define xchg(ptr, x)                                                           \
@@ -174,8 +236,10 @@ extern uint32_t __xchg_32(uint32_t i, volatile void *v);
 
 #define tas(ptr) (xchg((ptr), 1))
 
-#define atomic_cmpxchg(v, old, new) (cmpxchg(&((v)->counter), old, new))
-#define atomic_xchg(v, new) (xchg(&((v)->counter), new))
+#define atomic_cmpxchg(v, old, new)    (cmpxchg(&(v)->counter, old, new))
+#define atomic_xchg(v, new)            (xchg(&(v)->counter, new))
+#define atomic64_cmpxchg(v, old, new)  (__cmpxchg_64(old, new, &(v)->counter))
+#define atomic64_xchg(v, new)          (__xchg_64(new, &(v)->counter))
 
 static __inline__ int atomic_add_unless(atomic_t *v, int a, int u)
 {
diff --git a/arch/frv/include/asm/perf_counter.h b/arch/frv/include/asm/perf_counter.h
new file mode 100644 (file)
index 0000000..ccf726e
--- /dev/null
@@ -0,0 +1,17 @@
+/* FRV performance counter support
+ *
+ * Copyright (C) 2009 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+
+#ifndef _ASM_PERF_COUNTER_H
+#define _ASM_PERF_COUNTER_H
+
+#define PERF_COUNTER_INDEX_OFFSET      0
+
+#endif /* _ASM_PERF_COUNTER_H */
index 7742ec0..efd22d9 100644 (file)
@@ -208,6 +208,8 @@ extern void free_initmem(void);
  * - if (*ptr == test) then orig = *ptr; *ptr = test;
  * - if (*ptr != test) then orig = *ptr;
  */
+extern uint64_t __cmpxchg_64(uint64_t test, uint64_t new, volatile uint64_t *v);
+
 #ifndef CONFIG_FRV_OUTOFLINE_ATOMIC_OPS
 
 #define cmpxchg(ptr, test, new)                                                        \
index 96d78d5..4a8fb42 100644 (file)
 #define __NR_inotify_init1     332
 #define __NR_preadv            333
 #define __NR_pwritev           334
+#define __NR_rt_tgsigqueueinfo 335
+#define __NR_perf_counter_open 336
 
 #ifdef __KERNEL__
 
-#define NR_syscalls 335
+#define NR_syscalls 337
 
 #define __ARCH_WANT_IPC_PARSE_VERSION
 /* #define __ARCH_WANT_OLD_READDIR */
index 356e0e3..fde1e44 100644 (file)
@@ -1524,5 +1524,7 @@ sys_call_table:
        .long sys_inotify_init1
        .long sys_preadv
        .long sys_pwritev
+       .long sys_rt_tgsigqueueinfo     /* 335 */
+       .long sys_perf_counter_open
 
 syscall_table_size = (. - sys_call_table)
index 0316b3c..a89803b 100644 (file)
@@ -67,6 +67,10 @@ EXPORT_SYMBOL(atomic_sub_return);
 EXPORT_SYMBOL(__xchg_32);
 EXPORT_SYMBOL(__cmpxchg_32);
 #endif
+EXPORT_SYMBOL(atomic64_add_return);
+EXPORT_SYMBOL(atomic64_sub_return);
+EXPORT_SYMBOL(__xchg_64);
+EXPORT_SYMBOL(__cmpxchg_64);
 
 EXPORT_SYMBOL(__debug_bug_printk);
 EXPORT_SYMBOL(__delay_loops_MHz);
index 08be305..0a37721 100644 (file)
@@ -4,5 +4,5 @@
 
 lib-y := \
        __ashldi3.o __lshrdi3.o __muldi3.o __ashrdi3.o __negdi2.o __ucmpdi2.o \
-       checksum.o memcpy.o memset.o atomic-ops.o \
-       outsl_ns.o outsl_sw.o insl_ns.o insl_sw.o cache.o
+       checksum.o memcpy.o memset.o atomic-ops.o atomic64-ops.o \
+       outsl_ns.o outsl_sw.o insl_ns.o insl_sw.o cache.o perf_counter.o
index ee0ac90..5e9e6ab 100644 (file)
@@ -163,11 +163,10 @@ __cmpxchg_32:
        ld.p            @(gr11,gr0),gr8
        orcr            cc7,cc7,cc3
        subcc           gr8,gr9,gr7,icc0
-       bne             icc0,#0,1f
+       bnelr           icc0,#0
        cst.p           gr10,@(gr11,gr0)        ,cc3,#1
        corcc           gr29,gr29,gr0           ,cc3,#1
        beq             icc3,#0,0b
-1:
        bralr
 
        .size           __cmpxchg_32, .-__cmpxchg_32
diff --git a/arch/frv/lib/atomic64-ops.S b/arch/frv/lib/atomic64-ops.S
new file mode 100644 (file)
index 0000000..b6194ee
--- /dev/null
@@ -0,0 +1,162 @@
+/* kernel atomic64 operations
+ *
+ * For an explanation of how atomic ops work in this arch, see:
+ *   Documentation/frv/atomic-ops.txt
+ *
+ * Copyright (C) 2009 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.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 <asm/spr-regs.h>
+
+       .text
+       .balign 4
+
+
+###############################################################################
+#
+# long long atomic64_inc_return(atomic64_t *v)
+#
+###############################################################################
+       .globl          atomic64_inc_return
+        .type          atomic64_inc_return,@function
+atomic64_inc_return:
+       or.p            gr8,gr8,gr10
+0:
+       orcc            gr0,gr0,gr0,icc3                /* set ICC3.Z */
+       ckeq            icc3,cc7
+       ldd.p           @(gr10,gr0),gr8                 /* LDD.P/ORCR must be atomic */
+       orcr            cc7,cc7,cc3                     /* set CC3 to true */
+       addicc          gr9,#1,gr9,icc0
+       addxi           gr8,#0,gr8,icc0
+       cstd.p          gr8,@(gr10,gr0)         ,cc3,#1
+       corcc           gr29,gr29,gr0           ,cc3,#1 /* clear ICC3.Z if store happens */
+       beq             icc3,#0,0b
+       bralr
+
+       .size           atomic64_inc_return, .-atomic64_inc_return
+
+###############################################################################
+#
+# long long atomic64_dec_return(atomic64_t *v)
+#
+###############################################################################
+       .globl          atomic64_dec_return
+        .type          atomic64_dec_return,@function
+atomic64_dec_return:
+       or.p            gr8,gr8,gr10
+0:
+       orcc            gr0,gr0,gr0,icc3                /* set ICC3.Z */
+       ckeq            icc3,cc7
+       ldd.p           @(gr10,gr0),gr8                 /* LDD.P/ORCR must be atomic */
+       orcr            cc7,cc7,cc3                     /* set CC3 to true */
+       subicc          gr9,#1,gr9,icc0
+       subxi           gr8,#0,gr8,icc0
+       cstd.p          gr8,@(gr10,gr0)         ,cc3,#1
+       corcc           gr29,gr29,gr0           ,cc3,#1 /* clear ICC3.Z if store happens */
+       beq             icc3,#0,0b
+       bralr
+
+       .size           atomic64_dec_return, .-atomic64_dec_return
+
+###############################################################################
+#
+# long long atomic64_add_return(long long i, atomic64_t *v)
+#
+###############################################################################
+       .globl          atomic64_add_return
+        .type          atomic64_add_return,@function
+atomic64_add_return:
+       or.p            gr8,gr8,gr4
+       or              gr9,gr9,gr5
+0:
+       orcc            gr0,gr0,gr0,icc3                /* set ICC3.Z */
+       ckeq            icc3,cc7
+       ldd.p           @(gr10,gr0),gr8                 /* LDD.P/ORCR must be atomic */
+       orcr            cc7,cc7,cc3                     /* set CC3 to true */
+       addcc           gr9,gr5,gr9,icc0
+       addx            gr8,gr4,gr8,icc0
+       cstd.p          gr8,@(gr10,gr0)         ,cc3,#1
+       corcc           gr29,gr29,gr0           ,cc3,#1 /* clear ICC3.Z if store happens */
+       beq             icc3,#0,0b
+       bralr
+
+       .size           atomic64_add_return, .-atomic64_add_return
+
+###############################################################################
+#
+# long long atomic64_sub_return(long long i, atomic64_t *v)
+#
+###############################################################################
+       .globl          atomic64_sub_return
+        .type          atomic64_sub_return,@function
+atomic64_sub_return:
+       or.p            gr8,gr8,gr4
+       or              gr9,gr9,gr5
+0:
+       orcc            gr0,gr0,gr0,icc3                /* set ICC3.Z */
+       ckeq            icc3,cc7
+       ldd.p           @(gr10,gr0),gr8                 /* LDD.P/ORCR must be atomic */
+       orcr            cc7,cc7,cc3                     /* set CC3 to true */
+       subcc           gr9,gr5,gr9,icc0
+       subx            gr8,gr4,gr8,icc0
+       cstd.p          gr8,@(gr10,gr0)         ,cc3,#1
+       corcc           gr29,gr29,gr0           ,cc3,#1 /* clear ICC3.Z if store happens */
+       beq             icc3,#0,0b
+       bralr
+
+       .size           atomic64_sub_return, .-atomic64_sub_return
+
+###############################################################################
+#
+# uint64_t __xchg_64(uint64_t i, uint64_t *v)
+#
+###############################################################################
+       .globl          __xchg_64
+        .type          __xchg_64,@function
+__xchg_64:
+       or.p            gr8,gr8,gr4
+       or              gr9,gr9,gr5
+0:
+       orcc            gr0,gr0,gr0,icc3                /* set ICC3.Z */
+       ckeq            icc3,cc7
+       ldd.p           @(gr10,gr0),gr8                 /* LDD.P/ORCR must be atomic */
+       orcr            cc7,cc7,cc3                     /* set CC3 to true */
+       cstd.p          gr4,@(gr10,gr0)         ,cc3,#1
+       corcc           gr29,gr29,gr0           ,cc3,#1 /* clear ICC3.Z if store happens */
+       beq             icc3,#0,0b
+       bralr
+
+       .size           __xchg_64, .-__xchg_64
+
+###############################################################################
+#
+# uint64_t __cmpxchg_64(uint64_t test, uint64_t new, uint64_t *v)
+#
+###############################################################################
+       .globl          __cmpxchg_64
+        .type          __cmpxchg_64,@function
+__cmpxchg_64:
+       or.p            gr8,gr8,gr4
+       or              gr9,gr9,gr5
+0:
+       orcc            gr0,gr0,gr0,icc3                /* set ICC3.Z */
+       ckeq            icc3,cc7
+       ldd.p           @(gr12,gr0),gr8                 /* LDD.P/ORCR must be atomic */
+       orcr            cc7,cc7,cc3
+       subcc           gr8,gr4,gr0,icc0
+       subcc.p         gr9,gr5,gr0,icc1
+       bnelr           icc0,#0
+       bnelr           icc1,#0
+       cstd.p          gr10,@(gr12,gr0)        ,cc3,#1
+       corcc           gr29,gr29,gr0           ,cc3,#1 /* clear ICC3.Z if store happens */
+       beq             icc3,#0,0b
+       bralr
+
+       .size           __cmpxchg_64, .-__cmpxchg_64
+
diff --git a/arch/frv/lib/perf_counter.c b/arch/frv/lib/perf_counter.c
new file mode 100644 (file)
index 0000000..2000fee
--- /dev/null
@@ -0,0 +1,19 @@
+/* Performance counter handling
+ *
+ * Copyright (C) 2009 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+
+#include <linux/perf_counter.h>
+
+/*
+ * mark the performance counter as pending
+ */
+void set_perf_counter_pending(void)
+{
+}
index e4d8fde..7e81966 100644 (file)
@@ -412,7 +412,7 @@ simeth_tx(struct sk_buff *skb, struct net_device *dev)
         */
 
        dev_kfree_skb(skb);
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 static inline struct sk_buff *
index ebf4e98..d5764a3 100644 (file)
@@ -65,7 +65,7 @@ static int __init esi_init (void)
        }
 
        if (!esi)
-               return -ENODEV;;
+               return -ENODEV;
 
        systab = __va(esi);
 
index abce246..f178270 100644 (file)
@@ -5603,7 +5603,7 @@ pfm_interrupt_handler(int irq, void *arg)
  * /proc/perfmon interface, for debug only
  */
 
-#define PFM_PROC_SHOW_HEADER   ((void *)nr_cpu_ids+1)
+#define PFM_PROC_SHOW_HEADER   ((void *)(long)nr_cpu_ids+1)
 
 static void *
 pfm_proc_start(struct seq_file *m, loff_t *pos)
index 7053c55..e6676fc 100644 (file)
@@ -192,7 +192,7 @@ struct salinfo_platform_oemdata_parms {
 static void
 salinfo_work_to_do(struct salinfo_data *data)
 {
-       down_trylock(&data->mutex);
+       (void)(down_trylock(&data->mutex) ?: 0);
        up(&data->mutex);
 }
 
index a85cb61..f1268b8 100644 (file)
  *
  */
 #undef CONFIG_MODULES
+#include <linux/module.h>
+#undef CONFIG_KALLSYMS
+#undef EXPORT_SYMBOL
+#undef EXPORT_SYMBOL_GPL
+#define EXPORT_SYMBOL(sym)
+#define EXPORT_SYMBOL_GPL(sym)
 #include "../../../lib/vsprintf.c"
 #include "../../../lib/ctype.c"
index a8f84da..bb862fb 100644 (file)
@@ -130,7 +130,7 @@ static void collect_interruption(struct kvm_vcpu *vcpu)
        if (vdcr & IA64_DCR_PP) {
                vpsr |= IA64_PSR_PP;
        } else {
-               vpsr &= ~IA64_PSR_PP;;
+               vpsr &= ~IA64_PSR_PP;
        }
 
        vcpu_set_psr(vcpu, vpsr);
@@ -594,11 +594,11 @@ static void set_pal_call_data(struct kvm_vcpu *vcpu)
                p->u.pal_data.gr30 = vcpu_get_gr(vcpu, 30);
                break;
        case PAL_BRAND_INFO:
-               p->u.pal_data.gr29 = gr29;;
+               p->u.pal_data.gr29 = gr29;
                p->u.pal_data.gr30 = kvm_trans_pal_call_args(vcpu, gr30);
                break;
        default:
-               p->u.pal_data.gr29 = gr29;;
+               p->u.pal_data.gr29 = gr29;
                p->u.pal_data.gr30 = vcpu_get_gr(vcpu, 30);
        }
        p->u.pal_data.gr28 = gr28;
index a2c6c15..46b02cb 100644 (file)
@@ -406,7 +406,7 @@ void getreg(unsigned long regnum, unsigned long *val,
         * Now look at registers in [0-31] range and init correct UNAT
         */
        addr = (unsigned long)regs;
-       unat = &regs->eml_unat;;
+       unat = &regs->eml_unat;
 
        addr += gr_info[regnum];
 
index 4290a42..20b3852 100644 (file)
@@ -135,7 +135,7 @@ struct thash_data *__vtr_lookup(struct kvm_vcpu *vcpu, u64 va, int type)
        u64 rid;
 
        rid = vcpu_get_rr(vcpu, va);
-       rid = rid & RR_RID_MASK;;
+       rid = rid & RR_RID_MASK;
        if (type == D_TLB) {
                if (vcpu_quick_region_check(vcpu->arch.dtr_regions, va)) {
                        for (trp = (struct thash_data *)&vcpu->arch.dtrs, i = 0;
@@ -518,7 +518,7 @@ struct thash_data *vtlb_lookup(struct kvm_vcpu *v, u64 va, int is_data)
 
        struct thash_cb *hcb = &v->arch.vtlb;
 
-       cch = __vtr_lookup(v, va, is_data);;
+       cch = __vtr_lookup(v, va, is_data);
        if (cch)
                return cch;
 
index 76645cf..25831c4 100644 (file)
@@ -435,7 +435,8 @@ void sn_generate_path(struct pci_bus *pci_bus, char *address)
        bricktype = MODULE_GET_BTYPE(moduleid);
        if ((bricktype == L1_BRICKTYPE_191010) ||
            (bricktype == L1_BRICKTYPE_1932))
-                       sprintf(address, "%s^%d", address, geo_slot(geoid));
+                       sprintf(address + strlen(address), "^%d",
+                                               geo_slot(geoid));
 }
 
 void __devinit
index 8c4be1f..3ca0fe1 100644 (file)
@@ -22,6 +22,26 @@ choice
 config MACH_ALCHEMY
        bool "Alchemy processor based machines"
 
+config AR7
+       bool "Texas Instruments AR7"
+       select BOOT_ELF32
+       select DMA_NONCOHERENT
+       select CEVT_R4K
+       select CSRC_R4K
+       select IRQ_CPU
+       select NO_EXCEPT_FILL
+       select SWAP_IO_SPACE
+       select SYS_HAS_CPU_MIPS32_R1
+       select SYS_HAS_EARLY_PRINTK
+       select SYS_SUPPORTS_32BIT_KERNEL
+       select SYS_SUPPORTS_LITTLE_ENDIAN
+       select GENERIC_GPIO
+       select GCD
+       select VLYNQ
+       help
+         Support for the Texas Instruments AR7 System-on-a-Chip
+         family: TNETD7100, 7200 and 7300.
+
 config BASLER_EXCITE
        bool "Basler eXcite smart camera"
        select CEVT_R4K
@@ -209,7 +229,7 @@ config MIPS_MALTA
        select SYS_SUPPORTS_64BIT_KERNEL
        select SYS_SUPPORTS_BIG_ENDIAN
        select SYS_SUPPORTS_LITTLE_ENDIAN
-       select SYS_SUPPORTS_MIPS_CMP if BROKEN  # because SYNC_R4K is broken
+       select SYS_SUPPORTS_MIPS_CMP
        select SYS_SUPPORTS_MULTITHREADING
        select SYS_SUPPORTS_SMARTMIPS
        help
@@ -247,6 +267,7 @@ config MACH_VR41XX
        select CEVT_R4K
        select CSRC_R4K
        select SYS_HAS_CPU_VR41XX
+       select ARCH_REQUIRE_GPIOLIB
 
 config NXP_STB220
        bool "NXP STB220 board"
@@ -1635,7 +1656,7 @@ config MIPS_APSP_KSPD
 config MIPS_CMP
        bool "MIPS CMP framework support"
        depends on SYS_SUPPORTS_MIPS_CMP
-       select SYNC_R4K if BROKEN
+       select SYNC_R4K
        select SYS_SUPPORTS_SMP
        select SYS_SUPPORTS_SCHED_SMT if SMP
        select WEAK_ORDERING
@@ -2147,11 +2168,11 @@ menu "Power management options"
 
 config ARCH_HIBERNATION_POSSIBLE
        def_bool y
-       depends on SYS_SUPPORTS_HOTPLUG_CPU
+       depends on SYS_SUPPORTS_HOTPLUG_CPU || !SMP
 
 config ARCH_SUSPEND_POSSIBLE
        def_bool y
-       depends on SYS_SUPPORTS_HOTPLUG_CPU
+       depends on SYS_SUPPORTS_HOTPLUG_CPU || !SMP
 
 source "kernel/power/Kconfig"
 
index 807572a..861da51 100644 (file)
@@ -173,6 +173,13 @@ libs-y                             += arch/mips/fw/lib/
 #
 
 #
+# Texas Instruments AR7
+#
+core-$(CONFIG_AR7)             += arch/mips/ar7/
+cflags-$(CONFIG_AR7)           += -I$(srctree)/arch/mips/include/asm/mach-ar7
+load-$(CONFIG_AR7)             += 0xffffffff94100000
+
+#
 # Acer PICA 61, Mips Magnum 4000 and Olivetti M700.
 #
 core-$(CONFIG_MACH_JAZZ)       += arch/mips/jazz/
diff --git a/arch/mips/ar7/Makefile b/arch/mips/ar7/Makefile
new file mode 100644 (file)
index 0000000..7435e44
--- /dev/null
@@ -0,0 +1,10 @@
+
+obj-y := \
+       prom.o \
+       setup.o \
+       memory.o \
+       irq.o \
+       time.o \
+       platform.o \
+       gpio.o \
+       clock.o
diff --git a/arch/mips/ar7/clock.c b/arch/mips/ar7/clock.c
new file mode 100644 (file)
index 0000000..27dc666
--- /dev/null
@@ -0,0 +1,440 @@
+/*
+ * Copyright (C) 2007 Felix Fietkau <nbd@openwrt.org>
+ * Copyright (C) 2007 Eugene Konev <ejka@openwrt.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 program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/gcd.h>
+#include <linux/io.h>
+
+#include <asm/addrspace.h>
+#include <asm/mach-ar7/ar7.h>
+
+#define BOOT_PLL_SOURCE_MASK   0x3
+#define CPU_PLL_SOURCE_SHIFT   16
+#define BUS_PLL_SOURCE_SHIFT   14
+#define USB_PLL_SOURCE_SHIFT   18
+#define DSP_PLL_SOURCE_SHIFT   22
+#define BOOT_PLL_SOURCE_AFE    0
+#define BOOT_PLL_SOURCE_BUS    0
+#define BOOT_PLL_SOURCE_REF    1
+#define BOOT_PLL_SOURCE_XTAL   2
+#define BOOT_PLL_SOURCE_CPU    3
+#define BOOT_PLL_BYPASS                0x00000020
+#define BOOT_PLL_ASYNC_MODE    0x02000000
+#define BOOT_PLL_2TO1_MODE     0x00008000
+
+#define TNETD7200_CLOCK_ID_CPU 0
+#define TNETD7200_CLOCK_ID_DSP 1
+#define TNETD7200_CLOCK_ID_USB 2
+
+#define TNETD7200_DEF_CPU_CLK  211000000
+#define TNETD7200_DEF_DSP_CLK  125000000
+#define TNETD7200_DEF_USB_CLK  48000000
+
+struct tnetd7300_clock {
+       u32 ctrl;
+#define PREDIV_MASK    0x001f0000
+#define PREDIV_SHIFT   16
+#define POSTDIV_MASK   0x0000001f
+       u32 unused1[3];
+       u32 pll;
+#define MUL_MASK       0x0000f000
+#define MUL_SHIFT      12
+#define PLL_MODE_MASK  0x00000001
+#define PLL_NDIV       0x00000800
+#define PLL_DIV                0x00000002
+#define PLL_STATUS     0x00000001
+       u32 unused2[3];
+};
+
+struct tnetd7300_clocks {
+       struct tnetd7300_clock bus;
+       struct tnetd7300_clock cpu;
+       struct tnetd7300_clock usb;
+       struct tnetd7300_clock dsp;
+};
+
+struct tnetd7200_clock {
+       u32 ctrl;
+       u32 unused1[3];
+#define DIVISOR_ENABLE_MASK 0x00008000
+       u32 mul;
+       u32 prediv;
+       u32 postdiv;
+       u32 postdiv2;
+       u32 unused2[6];
+       u32 cmd;
+       u32 status;
+       u32 cmden;
+       u32 padding[15];
+};
+
+struct tnetd7200_clocks {
+       struct tnetd7200_clock cpu;
+       struct tnetd7200_clock dsp;
+       struct tnetd7200_clock usb;
+};
+
+int ar7_cpu_clock = 150000000;
+EXPORT_SYMBOL(ar7_cpu_clock);
+int ar7_bus_clock = 125000000;
+EXPORT_SYMBOL(ar7_bus_clock);
+int ar7_dsp_clock;
+EXPORT_SYMBOL(ar7_dsp_clock);
+
+static void approximate(int base, int target, int *prediv,
+                       int *postdiv, int *mul)
+{
+       int i, j, k, freq, res = target;
+       for (i = 1; i <= 16; i++)
+               for (j = 1; j <= 32; j++)
+                       for (k = 1; k <= 32; k++) {
+                               freq = abs(base / j * i / k - target);
+                               if (freq < res) {
+                                       res = freq;
+                                       *mul = i;
+                                       *prediv = j;
+                                       *postdiv = k;
+                               }
+                       }
+}
+
+static void calculate(int base, int target, int *prediv, int *postdiv,
+       int *mul)
+{
+       int tmp_gcd, tmp_base, tmp_freq;
+
+       for (*prediv = 1; *prediv <= 32; (*prediv)++) {
+               tmp_base = base / *prediv;
+               tmp_gcd = gcd(target, tmp_base);
+               *mul = target / tmp_gcd;
+               *postdiv = tmp_base / tmp_gcd;
+               if ((*mul < 1) || (*mul >= 16))
+                       continue;
+               if ((*postdiv > 0) & (*postdiv <= 32))
+                       break;
+       }
+
+       if (base / *prediv * *mul / *postdiv != target) {
+               approximate(base, target, prediv, postdiv, mul);
+               tmp_freq = base / *prediv * *mul / *postdiv;
+               printk(KERN_WARNING
+                      "Adjusted requested frequency %d to %d\n",
+                      target, tmp_freq);
+       }
+
+       printk(KERN_DEBUG "Clocks: prediv: %d, postdiv: %d, mul: %d\n",
+              *prediv, *postdiv, *mul);
+}
+
+static int tnetd7300_dsp_clock(void)
+{
+       u32 didr1, didr2;
+       u8 rev = ar7_chip_rev();
+       didr1 = readl((void *)KSEG1ADDR(AR7_REGS_GPIO + 0x18));
+       didr2 = readl((void *)KSEG1ADDR(AR7_REGS_GPIO + 0x1c));
+       if (didr2 & (1 << 23))
+               return 0;
+       if ((rev >= 0x23) && (rev != 0x57))
+               return 250000000;
+       if ((((didr2 & 0x1fff) << 10) | ((didr1 & 0xffc00000) >> 22))
+           > 4208000)
+               return 250000000;
+       return 0;
+}
+
+static int tnetd7300_get_clock(u32 shift, struct tnetd7300_clock *clock,
+       u32 *bootcr, u32 bus_clock)
+{
+       int product;
+       int base_clock = AR7_REF_CLOCK;
+       u32 ctrl = readl(&clock->ctrl);
+       u32 pll = readl(&clock->pll);
+       int prediv = ((ctrl & PREDIV_MASK) >> PREDIV_SHIFT) + 1;
+       int postdiv = (ctrl & POSTDIV_MASK) + 1;
+       int divisor = prediv * postdiv;
+       int mul = ((pll & MUL_MASK) >> MUL_SHIFT) + 1;
+
+       switch ((*bootcr & (BOOT_PLL_SOURCE_MASK << shift)) >> shift) {
+       case BOOT_PLL_SOURCE_BUS:
+               base_clock = bus_clock;
+               break;
+       case BOOT_PLL_SOURCE_REF:
+               base_clock = AR7_REF_CLOCK;
+               break;
+       case BOOT_PLL_SOURCE_XTAL:
+               base_clock = AR7_XTAL_CLOCK;
+               break;
+       case BOOT_PLL_SOURCE_CPU:
+               base_clock = ar7_cpu_clock;
+               break;
+       }
+
+       if (*bootcr & BOOT_PLL_BYPASS)
+               return base_clock / divisor;
+
+       if ((pll & PLL_MODE_MASK) == 0)
+               return (base_clock >> (mul / 16 + 1)) / divisor;
+
+       if ((pll & (PLL_NDIV | PLL_DIV)) == (PLL_NDIV | PLL_DIV)) {
+               product = (mul & 1) ?
+                       (base_clock * mul) >> 1 :
+                       (base_clock * (mul - 1)) >> 2;
+               return product / divisor;
+       }
+
+       if (mul == 16)
+               return base_clock / divisor;
+
+       return base_clock * mul / divisor;
+}
+
+static void tnetd7300_set_clock(u32 shift, struct tnetd7300_clock *clock,
+       u32 *bootcr, u32 frequency)
+{
+       int prediv, postdiv, mul;
+       int base_clock = ar7_bus_clock;
+
+       switch ((*bootcr & (BOOT_PLL_SOURCE_MASK << shift)) >> shift) {
+       case BOOT_PLL_SOURCE_BUS:
+               base_clock = ar7_bus_clock;
+               break;
+       case BOOT_PLL_SOURCE_REF:
+               base_clock = AR7_REF_CLOCK;
+               break;
+       case BOOT_PLL_SOURCE_XTAL:
+               base_clock = AR7_XTAL_CLOCK;
+               break;
+       case BOOT_PLL_SOURCE_CPU:
+               base_clock = ar7_cpu_clock;
+               break;
+       }
+
+       calculate(base_clock, frequency, &prediv, &postdiv, &mul);
+
+       writel(((prediv - 1) << PREDIV_SHIFT) | (postdiv - 1), &clock->ctrl);
+       msleep(1);
+       writel(4, &clock->pll);
+       while (readl(&clock->pll) & PLL_STATUS)
+               ;
+       writel(((mul - 1) << MUL_SHIFT) | (0xff << 3) | 0x0e, &clock->pll);
+       msleep(75);
+}
+
+static void __init tnetd7300_init_clocks(void)
+{
+       u32 *bootcr = (u32 *)ioremap_nocache(AR7_REGS_DCL, 4);
+       struct tnetd7300_clocks *clocks =
+                                       ioremap_nocache(UR8_REGS_CLOCKS,
+                                       sizeof(struct tnetd7300_clocks));
+
+       ar7_bus_clock = tnetd7300_get_clock(BUS_PLL_SOURCE_SHIFT,
+               &clocks->bus, bootcr, AR7_AFE_CLOCK);
+
+       if (*bootcr & BOOT_PLL_ASYNC_MODE)
+               ar7_cpu_clock = tnetd7300_get_clock(CPU_PLL_SOURCE_SHIFT,
+                       &clocks->cpu, bootcr, AR7_AFE_CLOCK);
+       else
+               ar7_cpu_clock = ar7_bus_clock;
+
+       if (ar7_dsp_clock == 250000000)
+               tnetd7300_set_clock(DSP_PLL_SOURCE_SHIFT, &clocks->dsp,
+                       bootcr, ar7_dsp_clock);
+
+       iounmap(clocks);
+       iounmap(bootcr);
+}
+
+static int tnetd7200_get_clock(int base, struct tnetd7200_clock *clock,
+       u32 *bootcr, u32 bus_clock)
+{
+       int divisor = ((readl(&clock->prediv) & 0x1f) + 1) *
+               ((readl(&clock->postdiv) & 0x1f) + 1);
+
+       if (*bootcr & BOOT_PLL_BYPASS)
+               return base / divisor;
+
+       return base * ((readl(&clock->mul) & 0xf) + 1) / divisor;
+}
+
+
+static void tnetd7200_set_clock(int base, struct tnetd7200_clock *clock,
+       int prediv, int postdiv, int postdiv2, int mul, u32 frequency)
+{
+       printk(KERN_INFO
+               "Clocks: base = %d, frequency = %u, prediv = %d, "
+               "postdiv = %d, postdiv2 = %d, mul = %d\n",
+               base, frequency, prediv, postdiv, postdiv2, mul);
+
+       writel(0, &clock->ctrl);
+       writel(DIVISOR_ENABLE_MASK | ((prediv - 1) & 0x1F), &clock->prediv);
+       writel((mul - 1) & 0xF, &clock->mul);
+
+       while (readl(&clock->status) & 0x1)
+               ; /* nop */
+
+       writel(DIVISOR_ENABLE_MASK | ((postdiv - 1) & 0x1F), &clock->postdiv);
+
+       writel(readl(&clock->cmden) | 1, &clock->cmden);
+       writel(readl(&clock->cmd) | 1, &clock->cmd);
+
+       while (readl(&clock->status) & 0x1)
+               ; /* nop */
+
+       writel(DIVISOR_ENABLE_MASK | ((postdiv2 - 1) & 0x1F), &clock->postdiv2);
+
+       writel(readl(&clock->cmden) | 1, &clock->cmden);
+       writel(readl(&clock->cmd) | 1, &clock->cmd);
+
+       while (readl(&clock->status) & 0x1)
+               ; /* nop */
+
+       writel(readl(&clock->ctrl) | 1, &clock->ctrl);
+}
+
+static int tnetd7200_get_clock_base(int clock_id, u32 *bootcr)
+{
+       if (*bootcr & BOOT_PLL_ASYNC_MODE)
+               /* Async */
+               switch (clock_id) {
+               case TNETD7200_CLOCK_ID_DSP:
+                       return AR7_REF_CLOCK;
+               default:
+                       return AR7_AFE_CLOCK;
+               }
+       else
+               /* Sync */
+               if (*bootcr & BOOT_PLL_2TO1_MODE)
+                       /* 2:1 */
+                       switch (clock_id) {
+                       case TNETD7200_CLOCK_ID_DSP:
+                               return AR7_REF_CLOCK;
+                       default:
+                               return AR7_AFE_CLOCK;
+                       }
+               else
+                       /* 1:1 */
+                       return AR7_REF_CLOCK;
+}
+
+
+static void __init tnetd7200_init_clocks(void)
+{
+       u32 *bootcr = (u32 *)ioremap_nocache(AR7_REGS_DCL, 4);
+       struct tnetd7200_clocks *clocks =
+                                       ioremap_nocache(AR7_REGS_CLOCKS,
+                                       sizeof(struct tnetd7200_clocks));
+       int cpu_base, cpu_mul, cpu_prediv, cpu_postdiv;
+       int dsp_base, dsp_mul, dsp_prediv, dsp_postdiv;
+       int usb_base, usb_mul, usb_prediv, usb_postdiv;
+
+       cpu_base = tnetd7200_get_clock_base(TNETD7200_CLOCK_ID_CPU, bootcr);
+       dsp_base = tnetd7200_get_clock_base(TNETD7200_CLOCK_ID_DSP, bootcr);
+
+       if (*bootcr & BOOT_PLL_ASYNC_MODE) {
+               printk(KERN_INFO "Clocks: Async mode\n");
+
+               printk(KERN_INFO "Clocks: Setting DSP clock\n");
+               calculate(dsp_base, TNETD7200_DEF_DSP_CLK,
+                       &dsp_prediv, &dsp_postdiv, &dsp_mul);
+               ar7_bus_clock =
+                       ((dsp_base / dsp_prediv) * dsp_mul) / dsp_postdiv;
+               tnetd7200_set_clock(dsp_base, &clocks->dsp,
+                       dsp_prediv, dsp_postdiv * 2, dsp_postdiv, dsp_mul * 2,
+                       ar7_bus_clock);
+
+               printk(KERN_INFO "Clocks: Setting CPU clock\n");
+               calculate(cpu_base, TNETD7200_DEF_CPU_CLK, &cpu_prediv,
+                       &cpu_postdiv, &cpu_mul);
+               ar7_cpu_clock =
+                       ((cpu_base / cpu_prediv) * cpu_mul) / cpu_postdiv;
+               tnetd7200_set_clock(cpu_base, &clocks->cpu,
+                       cpu_prediv, cpu_postdiv, -1, cpu_mul,
+                       ar7_cpu_clock);
+
+       } else
+               if (*bootcr & BOOT_PLL_2TO1_MODE) {
+                       printk(KERN_INFO "Clocks: Sync 2:1 mode\n");
+
+                       printk(KERN_INFO "Clocks: Setting CPU clock\n");
+                       calculate(cpu_base, TNETD7200_DEF_CPU_CLK, &cpu_prediv,
+                               &cpu_postdiv, &cpu_mul);
+                       ar7_cpu_clock = ((cpu_base / cpu_prediv) * cpu_mul)
+                                                               / cpu_postdiv;
+                       tnetd7200_set_clock(cpu_base, &clocks->cpu,
+                               cpu_prediv, cpu_postdiv, -1, cpu_mul,
+                               ar7_cpu_clock);
+
+                       printk(KERN_INFO "Clocks: Setting DSP clock\n");
+                       calculate(dsp_base, TNETD7200_DEF_DSP_CLK, &dsp_prediv,
+                               &dsp_postdiv, &dsp_mul);
+                       ar7_bus_clock = ar7_cpu_clock / 2;
+                       tnetd7200_set_clock(dsp_base, &clocks->dsp,
+                               dsp_prediv, dsp_postdiv * 2, dsp_postdiv,
+                               dsp_mul * 2, ar7_bus_clock);
+               } else {
+                       printk(KERN_INFO "Clocks: Sync 1:1 mode\n");
+
+                       printk(KERN_INFO "Clocks: Setting DSP clock\n");
+                       calculate(dsp_base, TNETD7200_DEF_DSP_CLK, &dsp_prediv,
+                               &dsp_postdiv, &dsp_mul);
+                       ar7_bus_clock = ((dsp_base / dsp_prediv) * dsp_mul)
+                                                               / dsp_postdiv;
+                       tnetd7200_set_clock(dsp_base, &clocks->dsp,
+                               dsp_prediv, dsp_postdiv * 2, dsp_postdiv,
+                               dsp_mul * 2, ar7_bus_clock);
+
+                       ar7_cpu_clock = ar7_bus_clock;
+               }
+
+       printk(KERN_INFO "Clocks: Setting USB clock\n");
+       usb_base = ar7_bus_clock;
+       calculate(usb_base, TNETD7200_DEF_USB_CLK, &usb_prediv,
+               &usb_postdiv, &usb_mul);
+       tnetd7200_set_clock(usb_base, &clocks->usb,
+               usb_prediv, usb_postdiv, -1, usb_mul,
+               TNETD7200_DEF_USB_CLK);
+
+       ar7_dsp_clock = ar7_cpu_clock;
+
+       iounmap(clocks);
+       iounmap(bootcr);
+}
+
+int __init ar7_init_clocks(void)
+{
+       switch (ar7_chip_id()) {
+       case AR7_CHIP_7100:
+       case AR7_CHIP_7200:
+               tnetd7200_init_clocks();
+               break;
+       case AR7_CHIP_7300:
+               ar7_dsp_clock = tnetd7300_dsp_clock();
+               tnetd7300_init_clocks();
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+arch_initcall(ar7_init_clocks);
diff --git a/arch/mips/ar7/gpio.c b/arch/mips/ar7/gpio.c
new file mode 100644 (file)
index 0000000..74e14a3
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2007 Felix Fietkau <nbd@openwrt.org>
+ * Copyright (C) 2007 Eugene Konev <ejka@openwrt.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 program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/module.h>
+
+#include <asm/mach-ar7/gpio.h>
+
+static const char *ar7_gpio_list[AR7_GPIO_MAX];
+
+int gpio_request(unsigned gpio, const char *label)
+{
+       if (gpio >= AR7_GPIO_MAX)
+               return -EINVAL;
+
+       if (ar7_gpio_list[gpio])
+               return -EBUSY;
+
+       if (label)
+               ar7_gpio_list[gpio] = label;
+       else
+               ar7_gpio_list[gpio] = "busy";
+
+       return 0;
+}
+EXPORT_SYMBOL(gpio_request);
+
+void gpio_free(unsigned gpio)
+{
+       BUG_ON(!ar7_gpio_list[gpio]);
+       ar7_gpio_list[gpio] = NULL;
+}
+EXPORT_SYMBOL(gpio_free);
diff --git a/arch/mips/ar7/irq.c b/arch/mips/ar7/irq.c
new file mode 100644 (file)
index 0000000..c781556
--- /dev/null
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2006,2007 Felix Fietkau <nbd@openwrt.org>
+ * Copyright (C) 2006,2007 Eugene Konev <ejka@openwrt.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 program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/interrupt.h>
+#include <linux/io.h>
+
+#include <asm/irq_cpu.h>
+#include <asm/mipsregs.h>
+#include <asm/mach-ar7/ar7.h>
+
+#define EXCEPT_OFFSET  0x80
+#define PACE_OFFSET    0xA0
+#define CHNLS_OFFSET   0x200
+
+#define REG_OFFSET(irq, reg)   ((irq) / 32 * 0x4 + reg * 0x10)
+#define SEC_REG_OFFSET(reg)    (EXCEPT_OFFSET + reg * 0x8)
+#define SEC_SR_OFFSET          (SEC_REG_OFFSET(0))     /* 0x80 */
+#define CR_OFFSET(irq)         (REG_OFFSET(irq, 1))    /* 0x10 */
+#define SEC_CR_OFFSET          (SEC_REG_OFFSET(1))     /* 0x88 */
+#define ESR_OFFSET(irq)                (REG_OFFSET(irq, 2))    /* 0x20 */
+#define SEC_ESR_OFFSET         (SEC_REG_OFFSET(2))     /* 0x90 */
+#define ECR_OFFSET(irq)                (REG_OFFSET(irq, 3))    /* 0x30 */
+#define SEC_ECR_OFFSET         (SEC_REG_OFFSET(3))     /* 0x98 */
+#define PIR_OFFSET             (0x40)
+#define MSR_OFFSET             (0x44)
+#define PM_OFFSET(irq)         (REG_OFFSET(irq, 5))    /* 0x50 */
+#define TM_OFFSET(irq)         (REG_OFFSET(irq, 6))    /* 0x60 */
+
+#define REG(addr) ((u32 *)(KSEG1ADDR(AR7_REGS_IRQ) + addr))
+
+#define CHNL_OFFSET(chnl) (CHNLS_OFFSET + (chnl * 4))
+
+static int ar7_irq_base;
+
+static void ar7_unmask_irq(unsigned int irq)
+{
+       writel(1 << ((irq - ar7_irq_base) % 32),
+              REG(ESR_OFFSET(irq - ar7_irq_base)));
+}
+
+static void ar7_mask_irq(unsigned int irq)
+{
+       writel(1 << ((irq - ar7_irq_base) % 32),
+              REG(ECR_OFFSET(irq - ar7_irq_base)));
+}
+
+static void ar7_ack_irq(unsigned int irq)
+{
+       writel(1 << ((irq - ar7_irq_base) % 32),
+              REG(CR_OFFSET(irq - ar7_irq_base)));
+}
+
+static void ar7_unmask_sec_irq(unsigned int irq)
+{
+       writel(1 << (irq - ar7_irq_base - 40), REG(SEC_ESR_OFFSET));
+}
+
+static void ar7_mask_sec_irq(unsigned int irq)
+{
+       writel(1 << (irq - ar7_irq_base - 40), REG(SEC_ECR_OFFSET));
+}
+
+static void ar7_ack_sec_irq(unsigned int irq)
+{
+       writel(1 << (irq - ar7_irq_base - 40), REG(SEC_CR_OFFSET));
+}
+
+static struct irq_chip ar7_irq_type = {
+       .name = "AR7",
+       .unmask = ar7_unmask_irq,
+       .mask = ar7_mask_irq,
+       .ack = ar7_ack_irq
+};
+
+static struct irq_chip ar7_sec_irq_type = {
+       .name = "AR7",
+       .unmask = ar7_unmask_sec_irq,
+       .mask = ar7_mask_sec_irq,
+       .ack = ar7_ack_sec_irq,
+};
+
+static struct irqaction ar7_cascade_action = {
+       .handler = no_action,
+       .name = "AR7 cascade interrupt"
+};
+
+static void __init ar7_irq_init(int base)
+{
+       int i;
+       /*
+        * Disable interrupts and clear pending
+        */
+       writel(0xffffffff, REG(ECR_OFFSET(0)));
+       writel(0xff, REG(ECR_OFFSET(32)));
+       writel(0xffffffff, REG(SEC_ECR_OFFSET));
+       writel(0xffffffff, REG(CR_OFFSET(0)));
+       writel(0xff, REG(CR_OFFSET(32)));
+       writel(0xffffffff, REG(SEC_CR_OFFSET));
+
+       ar7_irq_base = base;
+
+       for (i = 0; i < 40; i++) {
+               writel(i, REG(CHNL_OFFSET(i)));
+               /* Primary IRQ's */
+               set_irq_chip_and_handler(base + i, &ar7_irq_type,
+                                        handle_level_irq);
+               /* Secondary IRQ's */
+               if (i < 32)
+                       set_irq_chip_and_handler(base + i + 40,
+                                                &ar7_sec_irq_type,
+                                                handle_level_irq);
+       }
+
+       setup_irq(2, &ar7_cascade_action);
+       setup_irq(ar7_irq_base, &ar7_cascade_action);
+       set_c0_status(IE_IRQ0);
+}
+
+void __init arch_init_irq(void)
+{
+       mips_cpu_irq_init();
+       ar7_irq_init(8);
+}
+
+static void ar7_cascade(void)
+{
+       u32 status;
+       int i, irq;
+
+       /* Primary IRQ's */
+       irq = readl(REG(PIR_OFFSET)) & 0x3f;
+       if (irq) {
+               do_IRQ(ar7_irq_base + irq);
+               return;
+       }
+
+       /* Secondary IRQ's are cascaded through primary '0' */
+       writel(1, REG(CR_OFFSET(irq)));
+       status = readl(REG(SEC_SR_OFFSET));
+       for (i = 0; i < 32; i++) {
+               if (status & 1) {
+                       do_IRQ(ar7_irq_base + i + 40);
+                       return;
+               }
+               status >>= 1;
+       }
+
+       spurious_interrupt();
+}
+
+asmlinkage void plat_irq_dispatch(void)
+{
+       unsigned int pending = read_c0_status() & read_c0_cause() & ST0_IM;
+       if (pending & STATUSF_IP7)              /* cpu timer */
+               do_IRQ(7);
+       else if (pending & STATUSF_IP2)         /* int0 hardware line */
+               ar7_cascade();
+       else
+               spurious_interrupt();
+}
diff --git a/arch/mips/ar7/memory.c b/arch/mips/ar7/memory.c
new file mode 100644 (file)
index 0000000..46fed44
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2007 Felix Fietkau <nbd@openwrt.org>
+ * Copyright (C) 2007 Eugene Konev <ejka@openwrt.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 program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+#include <linux/bootmem.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/pfn.h>
+#include <linux/proc_fs.h>
+#include <linux/string.h>
+#include <linux/swap.h>
+
+#include <asm/bootinfo.h>
+#include <asm/page.h>
+#include <asm/sections.h>
+
+#include <asm/mach-ar7/ar7.h>
+#include <asm/mips-boards/prom.h>
+
+static int __init memsize(void)
+{
+       u32 size = (64 << 20);
+       u32 *addr = (u32 *)KSEG1ADDR(AR7_SDRAM_BASE + size - 4);
+       u32 *kernel_end = (u32 *)KSEG1ADDR(CPHYSADDR((u32)&_end));
+       u32 *tmpaddr = addr;
+
+       while (tmpaddr > kernel_end) {
+               *tmpaddr = (u32)tmpaddr;
+               size >>= 1;
+               tmpaddr -= size >> 2;
+       }
+
+       do {
+               tmpaddr += size >> 2;
+               if (*tmpaddr != (u32)tmpaddr)
+                       break;
+               size <<= 1;
+       } while (size < (64 << 20));
+
+       writel(tmpaddr, &addr);
+
+       return size;
+}
+
+void __init prom_meminit(void)
+{
+       unsigned long pages;
+
+       pages = memsize() >> PAGE_SHIFT;
+       add_memory_region(PHYS_OFFSET, pages << PAGE_SHIFT,
+                         BOOT_MEM_RAM);
+}
+
+void __init prom_free_prom_memory(void)
+{
+       /* Nothing to free */
+}
diff --git a/arch/mips/ar7/platform.c b/arch/mips/ar7/platform.c
new file mode 100644 (file)
index 0000000..5422449
--- /dev/null
@@ -0,0 +1,555 @@
+/*
+ * Copyright (C) 2006,2007 Felix Fietkau <nbd@openwrt.org>
+ * Copyright (C) 2006,2007 Eugene Konev <ejka@openwrt.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 program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/physmap.h>
+#include <linux/serial.h>
+#include <linux/serial_8250.h>
+#include <linux/ioport.h>
+#include <linux/io.h>
+#include <linux/version.h>
+#include <linux/vlynq.h>
+#include <linux/leds.h>
+#include <linux/string.h>
+#include <linux/etherdevice.h>
+
+#include <asm/addrspace.h>
+#include <asm/mach-ar7/ar7.h>
+#include <asm/mach-ar7/gpio.h>
+#include <asm/mach-ar7/prom.h>
+
+struct plat_vlynq_data {
+       struct plat_vlynq_ops ops;
+       int gpio_bit;
+       int reset_bit;
+};
+
+
+static int vlynq_on(struct vlynq_device *dev)
+{
+       int result;
+       struct plat_vlynq_data *pdata = dev->dev.platform_data;
+
+       result = gpio_request(pdata->gpio_bit, "vlynq");
+       if (result)
+               goto out;
+
+       ar7_device_reset(pdata->reset_bit);
+
+       result = ar7_gpio_disable(pdata->gpio_bit);
+       if (result)
+               goto out_enabled;
+
+       result = ar7_gpio_enable(pdata->gpio_bit);
+       if (result)
+               goto out_enabled;
+
+       result = gpio_direction_output(pdata->gpio_bit, 0);
+       if (result)
+               goto out_gpio_enabled;
+
+       msleep(50);
+
+       gpio_set_value(pdata->gpio_bit, 1);
+       msleep(50);
+
+       return 0;
+
+out_gpio_enabled:
+       ar7_gpio_disable(pdata->gpio_bit);
+out_enabled:
+       ar7_device_disable(pdata->reset_bit);
+       gpio_free(pdata->gpio_bit);
+out:
+       return result;
+}
+
+static void vlynq_off(struct vlynq_device *dev)
+{
+       struct plat_vlynq_data *pdata = dev->dev.platform_data;
+       ar7_gpio_disable(pdata->gpio_bit);
+       gpio_free(pdata->gpio_bit);
+       ar7_device_disable(pdata->reset_bit);
+}
+
+static struct resource physmap_flash_resource = {
+       .name = "mem",
+       .flags = IORESOURCE_MEM,
+       .start = 0x10000000,
+       .end = 0x107fffff,
+};
+
+static struct resource cpmac_low_res[] = {
+       {
+               .name = "regs",
+               .flags = IORESOURCE_MEM,
+               .start = AR7_REGS_MAC0,
+               .end = AR7_REGS_MAC0 + 0x7ff,
+       },
+       {
+               .name = "irq",
+               .flags = IORESOURCE_IRQ,
+               .start = 27,
+               .end = 27,
+       },
+};
+
+static struct resource cpmac_high_res[] = {
+       {
+               .name = "regs",
+               .flags = IORESOURCE_MEM,
+               .start = AR7_REGS_MAC1,
+               .end = AR7_REGS_MAC1 + 0x7ff,
+       },
+       {
+               .name = "irq",
+               .flags = IORESOURCE_IRQ,
+               .start = 41,
+               .end = 41,
+       },
+};
+
+static struct resource vlynq_low_res[] = {
+       {
+               .name = "regs",
+               .flags = IORESOURCE_MEM,
+               .start = AR7_REGS_VLYNQ0,
+               .end = AR7_REGS_VLYNQ0 + 0xff,
+       },
+       {
+               .name = "irq",
+               .flags = IORESOURCE_IRQ,
+               .start = 29,
+               .end = 29,
+       },
+       {
+               .name = "mem",
+               .flags = IORESOURCE_MEM,
+               .start = 0x04000000,
+               .end = 0x04ffffff,
+       },
+       {
+               .name = "devirq",
+               .flags = IORESOURCE_IRQ,
+               .start = 80,
+               .end = 111,
+       },
+};
+
+static struct resource vlynq_high_res[] = {
+       {
+               .name = "regs",
+               .flags = IORESOURCE_MEM,
+               .start = AR7_REGS_VLYNQ1,
+               .end = AR7_REGS_VLYNQ1 + 0xff,
+       },
+       {
+               .name = "irq",
+               .flags = IORESOURCE_IRQ,
+               .start = 33,
+               .end = 33,
+       },
+       {
+               .name = "mem",
+               .flags = IORESOURCE_MEM,
+               .start = 0x0c000000,
+               .end = 0x0cffffff,
+       },
+       {
+               .name = "devirq",
+               .flags = IORESOURCE_IRQ,
+               .start = 112,
+               .end = 143,
+       },
+};
+
+static struct resource usb_res[] = {
+       {
+               .name = "regs",
+               .flags = IORESOURCE_MEM,
+               .start = AR7_REGS_USB,
+               .end = AR7_REGS_USB + 0xff,
+       },
+       {
+               .name = "irq",
+               .flags = IORESOURCE_IRQ,
+               .start = 32,
+               .end = 32,
+       },
+       {
+               .name = "mem",
+               .flags = IORESOURCE_MEM,
+               .start = 0x03400000,
+               .end = 0x034001fff,
+       },
+};
+
+static struct physmap_flash_data physmap_flash_data = {
+       .width = 2,
+};
+
+static struct plat_cpmac_data cpmac_low_data = {
+       .reset_bit = 17,
+       .power_bit = 20,
+       .phy_mask = 0x80000000,
+};
+
+static struct plat_cpmac_data cpmac_high_data = {
+       .reset_bit = 21,
+       .power_bit = 22,
+       .phy_mask = 0x7fffffff,
+};
+
+static struct plat_vlynq_data vlynq_low_data = {
+       .ops.on = vlynq_on,
+       .ops.off = vlynq_off,
+       .reset_bit = 20,
+       .gpio_bit = 18,
+};
+
+static struct plat_vlynq_data vlynq_high_data = {
+       .ops.on = vlynq_on,
+       .ops.off = vlynq_off,
+       .reset_bit = 16,
+       .gpio_bit = 19,
+};
+
+static struct platform_device physmap_flash = {
+       .id = 0,
+       .name = "physmap-flash",
+       .dev.platform_data = &physmap_flash_data,
+       .resource = &physmap_flash_resource,
+       .num_resources = 1,
+};
+
+static u64 cpmac_dma_mask = DMA_32BIT_MASK;
+static struct platform_device cpmac_low = {
+       .id = 0,
+       .name = "cpmac",
+       .dev = {
+               .dma_mask = &cpmac_dma_mask,
+               .coherent_dma_mask = DMA_32BIT_MASK,
+               .platform_data = &cpmac_low_data,
+       },
+       .resource = cpmac_low_res,
+       .num_resources = ARRAY_SIZE(cpmac_low_res),
+};
+
+static struct platform_device cpmac_high = {
+       .id = 1,
+       .name = "cpmac",
+       .dev = {
+               .dma_mask = &cpmac_dma_mask,
+               .coherent_dma_mask = DMA_32BIT_MASK,
+               .platform_data = &cpmac_high_data,
+       },
+       .resource = cpmac_high_res,
+       .num_resources = ARRAY_SIZE(cpmac_high_res),
+};
+
+static struct platform_device vlynq_low = {
+       .id = 0,
+       .name = "vlynq",
+       .dev.platform_data = &vlynq_low_data,
+       .resource = vlynq_low_res,
+       .num_resources = ARRAY_SIZE(vlynq_low_res),
+};
+
+static struct platform_device vlynq_high = {
+       .id = 1,
+       .name = "vlynq",
+       .dev.platform_data = &vlynq_high_data,
+       .resource = vlynq_high_res,
+       .num_resources = ARRAY_SIZE(vlynq_high_res),
+};
+
+
+static struct gpio_led default_leds[] = {
+       {
+               .name = "status",
+               .gpio = 8,
+               .active_low = 1,
+       },
+};
+
+static struct gpio_led dsl502t_leds[] = {
+       {
+               .name = "status",
+               .gpio = 9,
+               .active_low = 1,
+       },
+       {
+               .name = "ethernet",
+               .gpio = 7,
+               .active_low = 1,
+       },
+       {
+               .name = "usb",
+               .gpio = 12,
+               .active_low = 1,
+       },
+};
+
+static struct gpio_led dg834g_leds[] = {
+       {
+               .name = "ppp",
+               .gpio = 6,
+               .active_low = 1,
+       },
+       {
+               .name = "status",
+               .gpio = 7,
+               .active_low = 1,
+       },
+       {
+               .name = "adsl",
+               .gpio = 8,
+               .active_low = 1,
+       },
+       {
+               .name = "wifi",
+               .gpio = 12,
+               .active_low = 1,
+       },
+       {
+               .name = "power",
+               .gpio = 14,
+               .active_low = 1,
+               .default_trigger = "default-on",
+       },
+};
+
+static struct gpio_led fb_sl_leds[] = {
+       {
+               .name = "1",
+               .gpio = 7,
+       },
+       {
+               .name = "2",
+               .gpio = 13,
+               .active_low = 1,
+       },
+       {
+               .name = "3",
+               .gpio = 10,
+               .active_low = 1,
+       },
+       {
+               .name = "4",
+               .gpio = 12,
+               .active_low = 1,
+       },
+       {
+               .name = "5",
+               .gpio = 9,
+               .active_low = 1,
+       },
+};
+
+static struct gpio_led fb_fon_leds[] = {
+       {
+               .name = "1",
+               .gpio = 8,
+       },
+       {
+               .name = "2",
+               .gpio = 3,
+               .active_low = 1,
+       },
+       {
+               .name = "3",
+               .gpio = 5,
+       },
+       {
+               .name = "4",
+               .gpio = 4,
+               .active_low = 1,
+       },
+       {
+               .name = "5",
+               .gpio = 11,
+               .active_low = 1,
+       },
+};
+
+static struct gpio_led_platform_data ar7_led_data;
+
+static struct platform_device ar7_gpio_leds = {
+       .name = "leds-gpio",
+       .id = -1,
+       .dev = {
+               .platform_data = &ar7_led_data,
+       }
+};
+
+static struct platform_device ar7_udc = {
+       .id = -1,
+       .name = "ar7_udc",
+       .resource = usb_res,
+       .num_resources = ARRAY_SIZE(usb_res),
+};
+
+static inline unsigned char char2hex(char h)
+{
+       switch (h) {
+       case '0': case '1': case '2': case '3': case '4':
+       case '5': case '6': case '7': case '8': case '9':
+               return h - '0';
+       case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
+               return h - 'A' + 10;
+       case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
+               return h - 'a' + 10;
+       default:
+               return 0;
+       }
+}
+
+static void cpmac_get_mac(int instance, unsigned char *dev_addr)
+{
+       int i;
+       char name[5], default_mac[ETH_ALEN], *mac;
+
+       mac = NULL;
+       sprintf(name, "mac%c", 'a' + instance);
+       mac = prom_getenv(name);
+       if (!mac) {
+               sprintf(name, "mac%c", 'a');
+               mac = prom_getenv(name);
+       }
+       if (!mac) {
+               random_ether_addr(default_mac);
+               mac = default_mac;
+       }
+       for (i = 0; i < 6; i++)
+               dev_addr[i] = (char2hex(mac[i * 3]) << 4) +
+                       char2hex(mac[i * 3 + 1]);
+}
+
+static void __init detect_leds(void)
+{
+       char *prid, *usb_prod;
+
+       /* Default LEDs */
+       ar7_led_data.num_leds = ARRAY_SIZE(default_leds);
+       ar7_led_data.leds = default_leds;
+
+       /* FIXME: the whole thing is unreliable */
+       prid = prom_getenv("ProductID");
+       usb_prod = prom_getenv("usb_prod");
+
+       /* If we can't get the product id from PROM, use the default LEDs */
+       if (!prid)
+               return;
+
+       if (strstr(prid, "Fritz_Box_FON")) {
+               ar7_led_data.num_leds = ARRAY_SIZE(fb_fon_leds);
+               ar7_led_data.leds = fb_fon_leds;
+       } else if (strstr(prid, "Fritz_Box_")) {
+               ar7_led_data.num_leds = ARRAY_SIZE(fb_sl_leds);
+               ar7_led_data.leds = fb_sl_leds;
+       } else if ((!strcmp(prid, "AR7RD") || !strcmp(prid, "AR7DB"))
+               && usb_prod != NULL && strstr(usb_prod, "DSL-502T")) {
+               ar7_led_data.num_leds = ARRAY_SIZE(dsl502t_leds);
+               ar7_led_data.leds = dsl502t_leds;
+       } else if (strstr(prid, "DG834")) {
+               ar7_led_data.num_leds = ARRAY_SIZE(dg834g_leds);
+               ar7_led_data.leds = dg834g_leds;
+       }
+}
+
+static int __init ar7_register_devices(void)
+{
+       int res;
+       static struct uart_port uart_port[2];
+
+       memset(uart_port, 0, sizeof(struct uart_port) * 2);
+
+       uart_port[0].type = PORT_16550A;
+       uart_port[0].line = 0;
+       uart_port[0].irq = AR7_IRQ_UART0;
+       uart_port[0].uartclk = ar7_bus_freq() / 2;
+       uart_port[0].iotype = UPIO_MEM32;
+       uart_port[0].mapbase = AR7_REGS_UART0;
+       uart_port[0].membase = ioremap(uart_port[0].mapbase, 256);
+       uart_port[0].regshift = 2;
+       res = early_serial_setup(&uart_port[0]);
+       if (res)
+               return res;
+
+
+       /* Only TNETD73xx have a second serial port */
+       if (ar7_has_second_uart()) {
+               uart_port[1].type = PORT_16550A;
+               uart_port[1].line = 1;
+               uart_port[1].irq = AR7_IRQ_UART1;
+               uart_port[1].uartclk = ar7_bus_freq() / 2;
+               uart_port[1].iotype = UPIO_MEM32;
+               uart_port[1].mapbase = UR8_REGS_UART1;
+               uart_port[1].membase = ioremap(uart_port[1].mapbase, 256);
+               uart_port[1].regshift = 2;
+               res = early_serial_setup(&uart_port[1]);
+               if (res)
+                       return res;
+       }
+
+       res = platform_device_register(&physmap_flash);
+       if (res)
+               return res;
+
+       ar7_device_disable(vlynq_low_data.reset_bit);
+       res = platform_device_register(&vlynq_low);
+       if (res)
+               return res;
+
+       if (ar7_has_high_vlynq()) {
+               ar7_device_disable(vlynq_high_data.reset_bit);
+               res = platform_device_register(&vlynq_high);
+               if (res)
+                       return res;
+       }
+
+       if (ar7_has_high_cpmac()) {
+               cpmac_get_mac(1, cpmac_high_data.dev_addr);
+               res = platform_device_register(&cpmac_high);
+               if (res)
+                       return res;
+       } else {
+               cpmac_low_data.phy_mask = 0xffffffff;
+       }
+
+       cpmac_get_mac(0, cpmac_low_data.dev_addr);
+       res = platform_device_register(&cpmac_low);
+       if (res)
+               return res;
+
+       detect_leds();
+       res = platform_device_register(&ar7_gpio_leds);
+       if (res)
+               return res;
+
+       res = platform_device_register(&ar7_udc);
+
+       return res;
+}
+arch_initcall(ar7_register_devices);
diff --git a/arch/mips/ar7/prom.c b/arch/mips/ar7/prom.c
new file mode 100644 (file)
index 0000000..a320bce
--- /dev/null
@@ -0,0 +1,297 @@
+/*
+ * Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 1999,2000 MIPS Technologies, Inc.  All rights reserved.
+ *
+ *  This program is free software; you can distribute 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 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.
+ *
+ * Putting things on the screen/serial line using YAMONs facilities.
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/serial_reg.h>
+#include <linux/spinlock.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/io.h>
+#include <asm/bootinfo.h>
+
+#include <asm/mach-ar7/ar7.h>
+#include <asm/mach-ar7/prom.h>
+
+#define MAX_ENTRY 80
+
+struct env_var {
+       char *name;
+       char *value;
+};
+
+static struct env_var adam2_env[MAX_ENTRY];
+
+char *prom_getenv(const char *name)
+{
+       int i;
+       for (i = 0; (i < MAX_ENTRY) && adam2_env[i].name; i++)
+               if (!strcmp(name, adam2_env[i].name))
+                       return adam2_env[i].value;
+
+       return NULL;
+}
+EXPORT_SYMBOL(prom_getenv);
+
+char * __init prom_getcmdline(void)
+{
+       return &(arcs_cmdline[0]);
+}
+
+static void  __init ar7_init_cmdline(int argc, char *argv[])
+{
+       char *cp;
+       int actr;
+
+       actr = 1; /* Always ignore argv[0] */
+
+       cp = &(arcs_cmdline[0]);
+       while (actr < argc) {
+               strcpy(cp, argv[actr]);
+               cp += strlen(argv[actr]);
+               *cp++ = ' ';
+               actr++;
+       }
+       if (cp != &(arcs_cmdline[0])) {
+               /* get rid of trailing space */
+               --cp;
+               *cp = '\0';
+       }
+}
+
+struct psbl_rec {
+       u32 psbl_size;
+       u32 env_base;
+       u32 env_size;
+       u32 ffs_base;
+       u32 ffs_size;
+};
+
+static __initdata char psp_env_version[] = "TIENV0.8";
+
+struct psp_env_chunk {
+       u8 num;
+       u8 ctrl;
+       u16 csum;
+       u8 len;
+       char data[11];
+} __attribute__ ((packed));
+
+struct psp_var_map_entry {
+       u8 num;
+       char *value;
+};
+
+static struct psp_var_map_entry psp_var_map[] = {
+       { 1, "cpufrequency" },
+       { 2, "memsize" },
+       { 3, "flashsize" },
+       { 4, "modetty0" },
+       { 5, "modetty1" },
+       { 8, "maca" },
+       { 9, "macb" },
+       { 28, "sysfrequency" },
+       { 38, "mipsfrequency" },
+};
+
+/*
+
+Well-known variable (num is looked up in table above for matching variable name)
+Example: cpufrequency=211968000
++----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+---
+| 01 |CTRL|CHECKSUM | 01 | _2 | _1 | _1 | _9 | _6 | _8 | _0 | _0 | _0 | \0 | FF
++----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+---
+
+Name=Value pair in a single chunk
+Example: NAME=VALUE
++----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+---
+| 00 |CTRL|CHECKSUM | 01 | _N | _A | _M | _E | _0 | _V | _A | _L | _U | _E | \0
++----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+---
+
+Name=Value pair in 2 chunks (len is the number of chunks)
+Example: bootloaderVersion=1.3.7.15
++----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+---
+| 00 |CTRL|CHECKSUM | 02 | _b | _o | _o | _t | _l | _o | _a | _d | _e | _r | _V
++----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+---
+| _e | _r | _s | _i | _o | _n | \0 | _1 | _. | _3 | _. | _7 | _. | _1 | _5 | \0
++----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+---
+
+Data is padded with 0xFF
+
+*/
+
+#define PSP_ENV_SIZE  4096
+
+static char psp_env_data[PSP_ENV_SIZE] = { 0, };
+
+static char * __init lookup_psp_var_map(u8 num)
+{
+       int i;
+
+       for (i = 0; i < sizeof(psp_var_map); i++)
+               if (psp_var_map[i].num == num)
+                       return psp_var_map[i].value;
+
+       return NULL;
+}
+
+static void __init add_adam2_var(char *name, char *value)
+{
+       int i;
+       for (i = 0; i < MAX_ENTRY; i++) {
+               if (!adam2_env[i].name) {
+                       adam2_env[i].name = name;
+                       adam2_env[i].value = value;
+                       return;
+               } else if (!strcmp(adam2_env[i].name, name)) {
+                       adam2_env[i].value = value;
+                       return;
+               }
+       }
+}
+
+static int __init parse_psp_env(void *psp_env_base)
+{
+       int i, n;
+       char *name, *value;
+       struct psp_env_chunk *chunks = (struct psp_env_chunk *)psp_env_data;
+
+       memcpy_fromio(chunks, psp_env_base, PSP_ENV_SIZE);
+
+       i = 1;
+       n = PSP_ENV_SIZE / sizeof(struct psp_env_chunk);
+       while (i < n) {
+               if ((chunks[i].num == 0xff) || ((i + chunks[i].len) > n))
+                       break;
+               value = chunks[i].data;
+               if (chunks[i].num) {
+                       name = lookup_psp_var_map(chunks[i].num);
+               } else {
+                       name = value;
+                       value += strlen(name) + 1;
+               }
+               if (name)
+                       add_adam2_var(name, value);
+               i += chunks[i].len;
+       }
+       return 0;
+}
+
+static void __init ar7_init_env(struct env_var *env)
+{
+       int i;
+       struct psbl_rec *psbl = (struct psbl_rec *)(KSEG1ADDR(0x14000300));
+       void *psp_env = (void *)KSEG1ADDR(psbl->env_base);
+
+       if (strcmp(psp_env, psp_env_version) == 0) {
+               parse_psp_env(psp_env);
+       } else {
+               for (i = 0; i < MAX_ENTRY; i++, env++)
+                       if (env->name)
+                               add_adam2_var(env->name, env->value);
+       }
+}
+
+static void __init console_config(void)
+{
+#ifdef CONFIG_SERIAL_8250_CONSOLE
+       char console_string[40];
+       int baud = 0;
+       char parity = '\0', bits = '\0', flow = '\0';
+       char *s, *p;
+
+       if (strstr(prom_getcmdline(), "console="))
+               return;
+
+#ifdef CONFIG_KGDB
+       if (!strstr(prom_getcmdline(), "nokgdb")) {
+               strcat(prom_getcmdline(), " console=kgdb");
+               kgdb_enabled = 1;
+               return;
+       }
+#endif
+
+       s = prom_getenv("modetty0");
+       if (s) {
+               baud = simple_strtoul(s, &p, 10);
+               s = p;
+               if (*s == ',')
+                       s++;
+               if (*s)
+                       parity = *s++;
+               if (*s == ',')
+                       s++;
+               if (*s)
+                       bits = *s++;
+               if (*s == ',')
+                       s++;
+               if (*s == 'h')
+                       flow = 'r';
+       }
+
+       if (baud == 0)
+               baud = 38400;
+       if (parity != 'n' && parity != 'o' && parity != 'e')
+               parity = 'n';
+       if (bits != '7' && bits != '8')
+               bits = '8';
+
+       if (flow == 'r')
+               sprintf(console_string, " console=ttyS0,%d%c%c%c", baud,
+                       parity, bits, flow);
+       else
+               sprintf(console_string, " console=ttyS0,%d%c%c", baud, parity,
+                       bits);
+       strcat(prom_getcmdline(), console_string);
+#endif
+}
+
+void __init prom_init(void)
+{
+       ar7_init_cmdline(fw_arg0, (char **)fw_arg1);
+       ar7_init_env((struct env_var *)fw_arg2);
+       console_config();
+}
+
+#define PORT(offset) (KSEG1ADDR(AR7_REGS_UART0 + (offset * 4)))
+static inline unsigned int serial_in(int offset)
+{
+       return readl((void *)PORT(offset));
+}
+
+static inline void serial_out(int offset, int value)
+{
+       writel(value, (void *)PORT(offset));
+}
+
+char prom_getchar(void)
+{
+       while (!(serial_in(UART_LSR) & UART_LSR_DR))
+               ;
+       return serial_in(UART_RX);
+}
+
+int prom_putchar(char c)
+{
+       while ((serial_in(UART_LSR) & UART_LSR_TEMT) == 0)
+               ;
+       serial_out(UART_TX, c);
+       return 1;
+}
+
diff --git a/arch/mips/ar7/setup.c b/arch/mips/ar7/setup.c
new file mode 100644 (file)
index 0000000..6ebb5f1
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 2000 MIPS Technologies, Inc.  All rights reserved.
+ *
+ *  This program is free software; you can distribute 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 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/version.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/pm.h>
+#include <linux/time.h>
+
+#include <asm/reboot.h>
+#include <asm/mach-ar7/ar7.h>
+#include <asm/mach-ar7/prom.h>
+
+static void ar7_machine_restart(char *command)
+{
+       u32 *softres_reg = ioremap(AR7_REGS_RESET +
+                                         AR7_RESET_SOFTWARE, 1);
+       writel(1, softres_reg);
+}
+
+static void ar7_machine_halt(void)
+{
+       while (1)
+               ;
+}
+
+static void ar7_machine_power_off(void)
+{
+       u32 *power_reg = (u32 *)ioremap(AR7_REGS_POWER, 1);
+       u32 power_state = readl(power_reg) | (3 << 30);
+       writel(power_state, power_reg);
+       ar7_machine_halt();
+}
+
+const char *get_system_type(void)
+{
+       u16 chip_id = ar7_chip_id();
+       switch (chip_id) {
+       case AR7_CHIP_7300:
+               return "TI AR7 (TNETD7300)";
+       case AR7_CHIP_7100:
+               return "TI AR7 (TNETD7100)";
+       case AR7_CHIP_7200:
+               return "TI AR7 (TNETD7200)";
+       default:
+               return "TI AR7 (Unknown)";
+       }
+}
+
+static int __init ar7_init_console(void)
+{
+       return 0;
+}
+console_initcall(ar7_init_console);
+
+/*
+ * Initializes basic routines and structures pointers, memory size (as
+ * given by the bios and saves the command line.
+ */
+
+void __init plat_mem_setup(void)
+{
+       unsigned long io_base;
+
+       _machine_restart = ar7_machine_restart;
+       _machine_halt = ar7_machine_halt;
+       pm_power_off = ar7_machine_power_off;
+       panic_timeout = 3;
+
+       io_base = (unsigned long)ioremap(AR7_REGS_BASE, 0x10000);
+       if (!io_base)
+               panic("Can't remap IO base!\n");
+       set_io_port_base(io_base);
+
+       prom_meminit();
+
+       printk(KERN_INFO "%s, ID: 0x%04x, Revision: 0x%02x\n",
+                                       get_system_type(),
+               ar7_chip_id(), ar7_chip_rev());
+}
diff --git a/arch/mips/ar7/time.c b/arch/mips/ar7/time.c
new file mode 100644 (file)
index 0000000..a1fba89
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 1999,2000 MIPS Technologies, Inc.  All rights reserved.
+ *
+ *  This program is free software; you can distribute 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 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.
+ *
+ * Setting up the clock on the MIPS boards.
+ */
+
+#include <linux/init.h>
+#include <linux/time.h>
+
+#include <asm/time.h>
+#include <asm/mach-ar7/ar7.h>
+
+void __init plat_time_init(void)
+{
+       mips_hpt_frequency = ar7_cpu_freq() / 2;
+}
index 7c0528b..d6903c3 100644 (file)
@@ -14,9 +14,5 @@ obj-y += dma-octeon.o flash_setup.o
 obj-y += octeon-memcpy.o
 
 obj-$(CONFIG_SMP)                     += smp.o
-obj-$(CONFIG_PCI)                     += pci-common.o
-obj-$(CONFIG_PCI)                     += pci.o
-obj-$(CONFIG_PCI)                     += pcie.o
-obj-$(CONFIG_PCI_MSI)                 += msi.o
 
 EXTRA_CFLAGS += -Werror
index 627c162..4b92bfc 100644 (file)
@@ -29,7 +29,7 @@
 #include <dma-coherence.h>
 
 #ifdef CONFIG_PCI
-#include "pci-common.h"
+#include <asm/octeon/pci-octeon.h>
 #endif
 
 #define BAR2_PCI_ADDRESS 0x8000000000ul
diff --git a/arch/mips/cavium-octeon/pci-common.c b/arch/mips/cavium-octeon/pci-common.c
deleted file mode 100644 (file)
index cd029f8..0000000
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 2005-2007 Cavium Networks
- */
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/interrupt.h>
-#include <linux/time.h>
-#include <linux/delay.h>
-#include "pci-common.h"
-
-typeof(pcibios_map_irq) *octeon_pcibios_map_irq;
-enum octeon_dma_bar_type octeon_dma_bar_type = OCTEON_DMA_BAR_TYPE_INVALID;
-
-/**
- * Map a PCI device to the appropriate interrupt line
- *
- * @param dev    The Linux PCI device structure for the device to map
- * @param slot   The slot number for this device on __BUS 0__. Linux
- *               enumerates through all the bridges and figures out the
- *               slot on Bus 0 where this device eventually hooks to.
- * @param pin    The PCI interrupt pin read from the device, then swizzled
- *               as it goes through each bridge.
- * @return Interrupt number for the device
- */
-int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
-{
-       if (octeon_pcibios_map_irq)
-               return octeon_pcibios_map_irq(dev, slot, pin);
-       else
-               panic("octeon_pcibios_map_irq doesn't point to a "
-                     "pcibios_map_irq() function");
-}
-
-
-/**
- * Called to perform platform specific PCI setup
- *
- * @param dev
- * @return
- */
-int pcibios_plat_dev_init(struct pci_dev *dev)
-{
-       uint16_t config;
-       uint32_t dconfig;
-       int pos;
-       /*
-        * Force the Cache line setting to 64 bytes. The standard
-        * Linux bus scan doesn't seem to set it. Octeon really has
-        * 128 byte lines, but Intel bridges get really upset if you
-        * try and set values above 64 bytes. Value is specified in
-        * 32bit words.
-        */
-       pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 64 / 4);
-       /* Set latency timers for all devices */
-       pci_write_config_byte(dev, PCI_LATENCY_TIMER, 48);
-
-       /* Enable reporting System errors and parity errors on all devices */
-       /* Enable parity checking and error reporting */
-       pci_read_config_word(dev, PCI_COMMAND, &config);
-       config |= PCI_COMMAND_PARITY | PCI_COMMAND_SERR;
-       pci_write_config_word(dev, PCI_COMMAND, config);
-
-       if (dev->subordinate) {
-               /* Set latency timers on sub bridges */
-               pci_write_config_byte(dev, PCI_SEC_LATENCY_TIMER, 48);
-               /* More bridge error detection */
-               pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &config);
-               config |= PCI_BRIDGE_CTL_PARITY | PCI_BRIDGE_CTL_SERR;
-               pci_write_config_word(dev, PCI_BRIDGE_CONTROL, config);
-       }
-
-       /* Enable the PCIe normal error reporting */
-       pos = pci_find_capability(dev, PCI_CAP_ID_EXP);
-       if (pos) {
-               /* Update Device Control */
-               pci_read_config_word(dev, pos + PCI_EXP_DEVCTL, &config);
-               /* Correctable Error Reporting */
-               config |= PCI_EXP_DEVCTL_CERE;
-               /* Non-Fatal Error Reporting */
-               config |= PCI_EXP_DEVCTL_NFERE;
-               /* Fatal Error Reporting */
-               config |= PCI_EXP_DEVCTL_FERE;
-               /* Unsupported Request */
-               config |= PCI_EXP_DEVCTL_URRE;
-               pci_write_config_word(dev, pos + PCI_EXP_DEVCTL, config);
-       }
-
-       /* Find the Advanced Error Reporting capability */
-       pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
-       if (pos) {
-               /* Clear Uncorrectable Error Status */
-               pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS,
-                                     &dconfig);
-               pci_write_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS,
-                                      dconfig);
-               /* Enable reporting of all uncorrectable errors */
-               /* Uncorrectable Error Mask - turned on bits disable errors */
-               pci_write_config_dword(dev, pos + PCI_ERR_UNCOR_MASK, 0);
-               /*
-                * Leave severity at HW default. This only controls if
-                * errors are reported as uncorrectable or
-                * correctable, not if the error is reported.
-                */
-               /* PCI_ERR_UNCOR_SEVER - Uncorrectable Error Severity */
-               /* Clear Correctable Error Status */
-               pci_read_config_dword(dev, pos + PCI_ERR_COR_STATUS, &dconfig);
-               pci_write_config_dword(dev, pos + PCI_ERR_COR_STATUS, dconfig);
-               /* Enable reporting of all correctable errors */
-               /* Correctable Error Mask - turned on bits disable errors */
-               pci_write_config_dword(dev, pos + PCI_ERR_COR_MASK, 0);
-               /* Advanced Error Capabilities */
-               pci_read_config_dword(dev, pos + PCI_ERR_CAP, &dconfig);
-               /* ECRC Generation Enable */
-               if (config & PCI_ERR_CAP_ECRC_GENC)
-                       config |= PCI_ERR_CAP_ECRC_GENE;
-               /* ECRC Check Enable */
-               if (config & PCI_ERR_CAP_ECRC_CHKC)
-                       config |= PCI_ERR_CAP_ECRC_CHKE;
-               pci_write_config_dword(dev, pos + PCI_ERR_CAP, dconfig);
-               /* PCI_ERR_HEADER_LOG - Header Log Register (16 bytes) */
-               /* Report all errors to the root complex */
-               pci_write_config_dword(dev, pos + PCI_ERR_ROOT_COMMAND,
-                                      PCI_ERR_ROOT_CMD_COR_EN |
-                                      PCI_ERR_ROOT_CMD_NONFATAL_EN |
-                                      PCI_ERR_ROOT_CMD_FATAL_EN);
-               /* Clear the Root status register */
-               pci_read_config_dword(dev, pos + PCI_ERR_ROOT_STATUS, &dconfig);
-               pci_write_config_dword(dev, pos + PCI_ERR_ROOT_STATUS, dconfig);
-       }
-
-       return 0;
-}
index 9e14398..4eaec8b 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  Cobalt buttons platform device.
  *
- *  Copyright (C) 2007  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *  Copyright (C) 2007  Yoichi Yuasa <yuasa@linux-mips.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
index 0720e4f..0f1cd90 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  Registration of Cobalt LCD platform device.
  *
- *  Copyright (C) 2008  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *  Copyright (C) 2008  Yoichi Yuasa <yuasa@linux-mips.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
index 1c6ebd4..d3ce6fa 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  Registration of Cobalt LED platform device.
  *
- *  Copyright (C) 2007  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *  Copyright (C) 2007  Yoichi Yuasa <yuasa@linux-mips.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
index 2b088ef..691d620 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  Registration of Cobalt MTD device.
  *
- *  Copyright (C) 2006  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *  Copyright (C) 2006  Yoichi Yuasa <yuasa@linux-mips.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
index e70794b..3ab3989 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  Registration of Cobalt RTC platform device.
  *
- *  Copyright (C) 2007  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *  Copyright (C) 2007  Yoichi Yuasa <yuasa@linux-mips.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
index 53b8d0d..7cb51f5 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  Registration of Cobalt UART platform device.
  *
- *  Copyright (C) 2007  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *  Copyright (C) 2007  Yoichi Yuasa <yuasa@linux-mips.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
index 4a570e7..0162f9e 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  Cobalt time initialization.
  *
- *  Copyright (C) 2007  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *  Copyright (C) 2007  Yoichi Yuasa <yuasa@linux-mips.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
diff --git a/arch/mips/configs/ar7_defconfig b/arch/mips/configs/ar7_defconfig
new file mode 100644 (file)
index 0000000..dad5b67
--- /dev/null
@@ -0,0 +1,1182 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.30
+# Wed Jun 24 14:08:59 2009
+#
+CONFIG_MIPS=y
+
+#
+# Machine selection
+#
+# CONFIG_MACH_ALCHEMY is not set
+CONFIG_AR7=y
+# CONFIG_BASLER_EXCITE is not set
+# CONFIG_BCM47XX is not set
+# CONFIG_MIPS_COBALT is not set
+# CONFIG_MACH_DECSTATION is not set
+# CONFIG_MACH_JAZZ is not set
+# CONFIG_LASAT is not set
+# CONFIG_LEMOTE_FULONG is not set
+# CONFIG_MIPS_MALTA is not set
+# CONFIG_MIPS_SIM is not set
+# CONFIG_NEC_MARKEINS is not set
+# CONFIG_MACH_VR41XX is not set
+# CONFIG_NXP_STB220 is not set
+# CONFIG_NXP_STB225 is not set
+# CONFIG_PNX8550_JBS is not set
+# CONFIG_PNX8550_STB810 is not set
+# CONFIG_PMC_MSP is not set
+# CONFIG_PMC_YOSEMITE is not set
+# CONFIG_SGI_IP22 is not set
+# CONFIG_SGI_IP27 is not set
+# CONFIG_SGI_IP28 is not set
+# CONFIG_SGI_IP32 is not set
+# CONFIG_SIBYTE_CRHINE is not set
+# CONFIG_SIBYTE_CARMEL is not set
+# CONFIG_SIBYTE_CRHONE is not set
+# CONFIG_SIBYTE_RHONE is not set
+# CONFIG_SIBYTE_SWARM is not set
+# CONFIG_SIBYTE_LITTLESUR is not set
+# CONFIG_SIBYTE_SENTOSA is not set
+# CONFIG_SIBYTE_BIGSUR is not set
+# CONFIG_SNI_RM is not set
+# CONFIG_MACH_TX39XX is not set
+# CONFIG_MACH_TX49XX is not set
+# CONFIG_MIKROTIK_RB532 is not set
+# CONFIG_WR_PPMC is not set
+# CONFIG_CAVIUM_OCTEON_SIMULATOR is not set
+# CONFIG_CAVIUM_OCTEON_REFERENCE_BOARD is not set
+# CONFIG_ALCHEMY_GPIO_INDIRECT is not set
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_ARCH_SUPPORTS_OPROFILE=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CMOS_UPDATE=y
+CONFIG_SCHED_OMIT_FRAME_POINTER=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
+CONFIG_CEVT_R4K_LIB=y
+CONFIG_CEVT_R4K=y
+CONFIG_CSRC_R4K_LIB=y
+CONFIG_CSRC_R4K=y
+CONFIG_DMA_NONCOHERENT=y
+CONFIG_DMA_NEED_PCI_MAP_STATE=y
+CONFIG_EARLY_PRINTK=y
+CONFIG_SYS_HAS_EARLY_PRINTK=y
+# CONFIG_HOTPLUG_CPU is not set
+# CONFIG_NO_IOPORT is not set
+CONFIG_GENERIC_GPIO=y
+# CONFIG_CPU_BIG_ENDIAN is not set
+CONFIG_CPU_LITTLE_ENDIAN=y
+CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y
+CONFIG_IRQ_CPU=y
+CONFIG_NO_EXCEPT_FILL=y
+CONFIG_SWAP_IO_SPACE=y
+CONFIG_BOOT_ELF32=y
+CONFIG_MIPS_L1_CACHE_SHIFT=5
+
+#
+# CPU selection
+#
+# CONFIG_CPU_LOONGSON2 is not set
+CONFIG_CPU_MIPS32_R1=y
+# CONFIG_CPU_MIPS32_R2 is not set
+# CONFIG_CPU_MIPS64_R1 is not set
+# CONFIG_CPU_MIPS64_R2 is not set
+# CONFIG_CPU_R3000 is not set
+# CONFIG_CPU_TX39XX is not set
+# CONFIG_CPU_VR41XX is not set
+# CONFIG_CPU_R4300 is not set
+# CONFIG_CPU_R4X00 is not set
+# CONFIG_CPU_TX49XX is not set
+# CONFIG_CPU_R5000 is not set
+# CONFIG_CPU_R5432 is not set
+# CONFIG_CPU_R5500 is not set
+# CONFIG_CPU_R6000 is not set
+# CONFIG_CPU_NEVADA is not set
+# CONFIG_CPU_R8000 is not set
+# CONFIG_CPU_R10000 is not set
+# CONFIG_CPU_RM7000 is not set
+# CONFIG_CPU_RM9000 is not set
+# CONFIG_CPU_SB1 is not set
+# CONFIG_CPU_CAVIUM_OCTEON is not set
+CONFIG_SYS_HAS_CPU_MIPS32_R1=y
+CONFIG_CPU_MIPS32=y
+CONFIG_CPU_MIPSR1=y
+CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
+CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
+CONFIG_HARDWARE_WATCHPOINTS=y
+
+#
+# Kernel type
+#
+CONFIG_32BIT=y
+# CONFIG_64BIT is not set
+CONFIG_PAGE_SIZE_4KB=y
+# CONFIG_PAGE_SIZE_8KB is not set
+# CONFIG_PAGE_SIZE_16KB is not set
+# CONFIG_PAGE_SIZE_32KB is not set
+# CONFIG_PAGE_SIZE_64KB is not set
+CONFIG_CPU_HAS_PREFETCH=y
+CONFIG_MIPS_MT_DISABLED=y
+# CONFIG_MIPS_MT_SMP is not set
+# CONFIG_MIPS_MT_SMTC is not set
+CONFIG_CPU_HAS_LLSC=y
+CONFIG_CPU_HAS_SYNC=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_CPU_SUPPORTS_HIGHMEM=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_POPULATES_NODE_MAP=y
+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_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_VIRT_TO_BUS=y
+CONFIG_HAVE_MLOCK=y
+CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
+CONFIG_TICK_ONESHOT=y
+# CONFIG_NO_HZ is not set
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+# CONFIG_HZ_48 is not set
+CONFIG_HZ_100=y
+# CONFIG_HZ_128 is not set
+# CONFIG_HZ_250 is not set
+# CONFIG_HZ_256 is not set
+# CONFIG_HZ_1000 is not set
+# CONFIG_HZ_1024 is not set
+CONFIG_SYS_SUPPORTS_ARBIT_HZ=y
+CONFIG_HZ=100
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+CONFIG_KEXEC=y
+# CONFIG_SECCOMP is not set
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_AUDIT is not set
+
+#
+# RCU Subsystem
+#
+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_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_GROUP_SCHED is not set
+# CONFIG_CGROUPS is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_RELAY=y
+# CONFIG_NAMESPACES is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_RD_GZIP=y
+# CONFIG_RD_BZIP2 is not set
+CONFIG_RD_LZMA=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
+CONFIG_EMBEDDED=y
+CONFIG_SYSCTL_SYSCALL=y
+# CONFIG_KALLSYMS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+# CONFIG_ELF_CORE is not set
+# CONFIG_PCSPKR_PLATFORM is not set
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_AIO=y
+
+#
+# Performance Counters
+#
+# CONFIG_VM_EVENT_COUNTERS is not set
+CONFIG_STRIP_ASM_SYMS=y
+# CONFIG_COMPAT_BRK is not set
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+# CONFIG_PROFILING is not set
+# CONFIG_MARKERS is not set
+CONFIG_HAVE_OPROFILE=y
+# CONFIG_SLOW_WORK is not set
+# 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 is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_BLOCK=y
+# CONFIG_LBD 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 is not set
+CONFIG_IOSCHED_DEADLINE=y
+# CONFIG_IOSCHED_CFQ is not set
+# CONFIG_DEFAULT_AS is not set
+CONFIG_DEFAULT_DEADLINE=y
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="deadline"
+CONFIG_PROBE_INITRD_HEADER=y
+# CONFIG_FREEZER is not set
+
+#
+# Bus options (PCI, PCMCIA, EISA, ISA, TC)
+#
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+CONFIG_MMU=y
+# CONFIG_PCCARD is not set
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_HAVE_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+CONFIG_TRAD_SIGNALS=y
+
+#
+# Power management options
+#
+CONFIG_ARCH_HIBERNATION_POSSIBLE=y
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+# CONFIG_PM is not set
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_ASK_IP_FIB_HASH=y
+# CONFIG_IP_FIB_TRIE is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_MULTIPATH=y
+CONFIG_IP_ROUTE_VERBOSE=y
+# CONFIG_IP_PNP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+CONFIG_IP_MROUTE=y
+# CONFIG_IP_PIMSM_V1 is not set
+# CONFIG_IP_PIMSM_V2 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 is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+# CONFIG_INET_DIAG is not set
+CONFIG_TCP_CONG_ADVANCED=y
+# CONFIG_TCP_CONG_BIC is not set
+# CONFIG_TCP_CONG_CUBIC is not set
+CONFIG_TCP_CONG_WESTWOOD=y
+# CONFIG_TCP_CONG_HTCP is not set
+# CONFIG_TCP_CONG_HSTCP is not set
+# CONFIG_TCP_CONG_HYBLA is not set
+# CONFIG_TCP_CONG_VEGAS is not set
+# CONFIG_TCP_CONG_SCALABLE is not set
+# CONFIG_TCP_CONG_LP is not set
+# CONFIG_TCP_CONG_VENO is not set
+# CONFIG_TCP_CONG_YEAH is not set
+# CONFIG_TCP_CONG_ILLINOIS is not set
+# CONFIG_DEFAULT_BIC is not set
+# CONFIG_DEFAULT_CUBIC is not set
+# CONFIG_DEFAULT_HTCP is not set
+# CONFIG_DEFAULT_VEGAS is not set
+CONFIG_DEFAULT_WESTWOOD=y
+# CONFIG_DEFAULT_RENO is not set
+CONFIG_DEFAULT_TCP_CONG="westwood"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETWORK_SECMARK is not set
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+CONFIG_NETFILTER_ADVANCED=y
+# CONFIG_BRIDGE_NETFILTER is not set
+
+#
+# Core Netfilter Configuration
+#
+# CONFIG_NETFILTER_NETLINK_QUEUE is not set
+# CONFIG_NETFILTER_NETLINK_LOG is not set
+CONFIG_NF_CONNTRACK=m
+# CONFIG_NF_CT_ACCT is not set
+CONFIG_NF_CONNTRACK_MARK=y
+# CONFIG_NF_CONNTRACK_EVENTS is not set
+# CONFIG_NF_CT_PROTO_DCCP is not set
+# CONFIG_NF_CT_PROTO_SCTP is not set
+# CONFIG_NF_CT_PROTO_UDPLITE is not set
+# CONFIG_NF_CONNTRACK_AMANDA is not set
+CONFIG_NF_CONNTRACK_FTP=m
+# CONFIG_NF_CONNTRACK_H323 is not set
+CONFIG_NF_CONNTRACK_IRC=m
+# CONFIG_NF_CONNTRACK_NETBIOS_NS is not set
+# CONFIG_NF_CONNTRACK_PPTP is not set
+# CONFIG_NF_CONNTRACK_SANE is not set
+# CONFIG_NF_CONNTRACK_SIP is not set
+CONFIG_NF_CONNTRACK_TFTP=m
+# CONFIG_NF_CT_NETLINK is not set
+# CONFIG_NETFILTER_TPROXY is not set
+CONFIG_NETFILTER_XTABLES=m
+# CONFIG_NETFILTER_XT_TARGET_CLASSIFY is not set
+# CONFIG_NETFILTER_XT_TARGET_CONNMARK is not set
+# CONFIG_NETFILTER_XT_TARGET_DSCP is not set
+# CONFIG_NETFILTER_XT_TARGET_HL is not set
+# CONFIG_NETFILTER_XT_TARGET_LED is not set
+# CONFIG_NETFILTER_XT_TARGET_MARK is not set
+# CONFIG_NETFILTER_XT_TARGET_NFLOG is not set
+# CONFIG_NETFILTER_XT_TARGET_NFQUEUE is not set
+CONFIG_NETFILTER_XT_TARGET_NOTRACK=m
+# CONFIG_NETFILTER_XT_TARGET_RATEEST is not set
+# CONFIG_NETFILTER_XT_TARGET_TRACE is not set
+CONFIG_NETFILTER_XT_TARGET_TCPMSS=m
+# CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP is not set
+# CONFIG_NETFILTER_XT_MATCH_CLUSTER is not set
+# CONFIG_NETFILTER_XT_MATCH_COMMENT is not set
+# CONFIG_NETFILTER_XT_MATCH_CONNBYTES is not set
+# CONFIG_NETFILTER_XT_MATCH_CONNLIMIT is not set
+# CONFIG_NETFILTER_XT_MATCH_CONNMARK is not set
+# CONFIG_NETFILTER_XT_MATCH_CONNTRACK is not set
+# CONFIG_NETFILTER_XT_MATCH_DCCP is not set
+# CONFIG_NETFILTER_XT_MATCH_DSCP is not set
+# CONFIG_NETFILTER_XT_MATCH_ESP is not set
+# CONFIG_NETFILTER_XT_MATCH_HASHLIMIT is not set
+# CONFIG_NETFILTER_XT_MATCH_HELPER is not set
+# CONFIG_NETFILTER_XT_MATCH_HL is not set
+# CONFIG_NETFILTER_XT_MATCH_IPRANGE is not set
+# CONFIG_NETFILTER_XT_MATCH_LENGTH is not set
+CONFIG_NETFILTER_XT_MATCH_LIMIT=m
+CONFIG_NETFILTER_XT_MATCH_MAC=m
+# CONFIG_NETFILTER_XT_MATCH_MARK is not set
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m
+# CONFIG_NETFILTER_XT_MATCH_OWNER is not set
+# CONFIG_NETFILTER_XT_MATCH_PKTTYPE is not set
+# CONFIG_NETFILTER_XT_MATCH_QUOTA is not set
+# CONFIG_NETFILTER_XT_MATCH_RATEEST is not set
+# CONFIG_NETFILTER_XT_MATCH_REALM is not set
+# CONFIG_NETFILTER_XT_MATCH_RECENT is not set
+# CONFIG_NETFILTER_XT_MATCH_SCTP is not set
+CONFIG_NETFILTER_XT_MATCH_STATE=m
+# CONFIG_NETFILTER_XT_MATCH_STATISTIC is not set
+# CONFIG_NETFILTER_XT_MATCH_STRING is not set
+# CONFIG_NETFILTER_XT_MATCH_TCPMSS is not set
+# CONFIG_NETFILTER_XT_MATCH_TIME is not set
+# CONFIG_NETFILTER_XT_MATCH_U32 is not set
+# CONFIG_IP_VS is not set
+
+#
+# IP: Netfilter Configuration
+#
+CONFIG_NF_DEFRAG_IPV4=m
+CONFIG_NF_CONNTRACK_IPV4=m
+CONFIG_NF_CONNTRACK_PROC_COMPAT=y
+# CONFIG_IP_NF_QUEUE is not set
+CONFIG_IP_NF_IPTABLES=m
+# CONFIG_IP_NF_MATCH_ADDRTYPE is not set
+# CONFIG_IP_NF_MATCH_AH is not set
+# CONFIG_IP_NF_MATCH_ECN is not set
+# CONFIG_IP_NF_MATCH_TTL is not set
+CONFIG_IP_NF_FILTER=m
+CONFIG_IP_NF_TARGET_REJECT=m
+CONFIG_IP_NF_TARGET_LOG=m
+# CONFIG_IP_NF_TARGET_ULOG is not set
+CONFIG_NF_NAT=m
+CONFIG_NF_NAT_NEEDED=y
+CONFIG_IP_NF_TARGET_MASQUERADE=m
+# CONFIG_IP_NF_TARGET_NETMAP is not set
+# CONFIG_IP_NF_TARGET_REDIRECT is not set
+# CONFIG_NF_NAT_SNMP_BASIC is not set
+CONFIG_NF_NAT_FTP=m
+CONFIG_NF_NAT_IRC=m
+CONFIG_NF_NAT_TFTP=m
+# CONFIG_NF_NAT_AMANDA is not set
+# CONFIG_NF_NAT_PPTP is not set
+# CONFIG_NF_NAT_H323 is not set
+# CONFIG_NF_NAT_SIP is not set
+CONFIG_IP_NF_MANGLE=m
+# CONFIG_IP_NF_TARGET_CLUSTERIP is not set
+# CONFIG_IP_NF_TARGET_ECN is not set
+# CONFIG_IP_NF_TARGET_TTL is not set
+CONFIG_IP_NF_RAW=m
+# CONFIG_IP_NF_ARPTABLES is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_TIPC is not set
+CONFIG_ATM=m
+# CONFIG_ATM_CLIP is not set
+# CONFIG_ATM_LANE is not set
+CONFIG_ATM_BR2684=m
+CONFIG_ATM_BR2684_IPFILTER=y
+CONFIG_STP=y
+CONFIG_BRIDGE=y
+# CONFIG_NET_DSA is not set
+CONFIG_VLAN_8021Q=y
+# CONFIG_VLAN_8021Q_GVRP is not set
+# CONFIG_DECNET is not set
+CONFIG_LLC=y
+# 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_PHONET is not set
+# CONFIG_IEEE802154 is not set
+CONFIG_NET_SCHED=y
+
+#
+# Queueing/Scheduling
+#
+# CONFIG_NET_SCH_CBQ is not set
+# CONFIG_NET_SCH_HTB is not set
+# CONFIG_NET_SCH_HFSC is not set
+# CONFIG_NET_SCH_ATM is not set
+# CONFIG_NET_SCH_PRIO is not set
+# CONFIG_NET_SCH_MULTIQ is not set
+# CONFIG_NET_SCH_RED is not set
+# CONFIG_NET_SCH_SFQ is not set
+# CONFIG_NET_SCH_TEQL is not set
+# CONFIG_NET_SCH_TBF is not set
+# CONFIG_NET_SCH_GRED is not set
+# CONFIG_NET_SCH_DSMARK is not set
+# CONFIG_NET_SCH_NETEM is not set
+# CONFIG_NET_SCH_DRR is not set
+# CONFIG_NET_SCH_INGRESS is not set
+
+#
+# Classification
+#
+# CONFIG_NET_CLS_BASIC is not set
+# CONFIG_NET_CLS_TCINDEX is not set
+# CONFIG_NET_CLS_ROUTE4 is not set
+# CONFIG_NET_CLS_FW is not set
+# CONFIG_NET_CLS_U32 is not set
+# CONFIG_NET_CLS_RSVP is not set
+# CONFIG_NET_CLS_RSVP6 is not set
+# CONFIG_NET_CLS_FLOW is not set
+# CONFIG_NET_EMATCH is not set
+CONFIG_NET_CLS_ACT=y
+CONFIG_NET_ACT_POLICE=y
+# CONFIG_NET_ACT_GACT is not set
+# CONFIG_NET_ACT_MIRRED is not set
+# CONFIG_NET_ACT_IPT is not set
+# CONFIG_NET_ACT_NAT is not set
+# CONFIG_NET_ACT_PEDIT is not set
+# CONFIG_NET_ACT_SIMP is not set
+# CONFIG_NET_ACT_SKBEDIT is not set
+CONFIG_NET_SCH_FIFO=y
+# CONFIG_DCB is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+CONFIG_HAMRADIO=y
+
+#
+# Packet Radio protocols
+#
+# CONFIG_AX25 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_FIB_RULES=y
+CONFIG_WIRELESS=y
+CONFIG_CFG80211=m
+# CONFIG_CFG80211_REG_DEBUG is not set
+# CONFIG_CFG80211_DEBUGFS is not set
+# CONFIG_WIRELESS_OLD_REGULATORY is not set
+CONFIG_WIRELESS_EXT=y
+CONFIG_WIRELESS_EXT_SYSFS=y
+# CONFIG_LIB80211 is not set
+CONFIG_MAC80211=m
+CONFIG_MAC80211_DEFAULT_PS=y
+CONFIG_MAC80211_DEFAULT_PS_VALUE=1
+
+#
+# Rate control algorithm selection
+#
+CONFIG_MAC80211_RC_PID=y
+CONFIG_MAC80211_RC_MINSTREL=y
+CONFIG_MAC80211_RC_DEFAULT_PID=y
+# CONFIG_MAC80211_RC_DEFAULT_MINSTREL is not set
+CONFIG_MAC80211_RC_DEFAULT="pid"
+# CONFIG_MAC80211_MESH is not set
+# CONFIG_MAC80211_LEDS is not set
+# CONFIG_MAC80211_DEBUGFS is not set
+# CONFIG_MAC80211_DEBUG_MENU 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 is not set
+CONFIG_EXTRA_FIRMWARE=""
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_TESTS is not set
+# CONFIG_MTD_REDBOOT_PARTS is not set
+# CONFIG_MTD_CMDLINE_PARTS is not set
+# CONFIG_MTD_AR7_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_CFI_INTELEXT=y
+CONFIG_MTD_CFI_AMDSTD=y
+CONFIG_MTD_CFI_STAA=y
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+CONFIG_MTD_COMPLEX_MAPPINGS=y
+CONFIG_MTD_PHYSMAP=y
+# CONFIG_MTD_PHYSMAP_COMPAT is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+# CONFIG_MTD_NAND is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# LPDDR flash memory drivers
+#
+# CONFIG_MTD_LPDDR is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+# CONFIG_BLK_DEV_HD is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_ENCLOSURE_SERVICES is not set
+# CONFIG_C2PORT is not set
+
+#
+# EEPROM support
+#
+# CONFIG_EEPROM_93CX6 is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+# CONFIG_SCSI_DMA is not set
+# CONFIG_SCSI_NETLINK is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+CONFIG_NETDEVICES=y
+# CONFIG_IFB is not set
+# CONFIG_DUMMY is not set
+# 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_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=y
+# CONFIG_MDIO_BITBANG is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_AX88796 is not set
+# CONFIG_SMC91X is not set
+# CONFIG_DM9000 is not set
+# CONFIG_ETHOC is not set
+# CONFIG_DNET 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_B44 is not set
+# CONFIG_KS8842 is not set
+CONFIG_CPMAC=y
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+CONFIG_WLAN_80211=y
+# CONFIG_LIBERTAS is not set
+# CONFIG_LIBERTAS_THINFIRM is not set
+# CONFIG_MAC80211_HWSIM is not set
+# CONFIG_P54_COMMON is not set
+# CONFIG_HOSTAP is not set
+# CONFIG_B43 is not set
+# CONFIG_B43LEGACY is not set
+# CONFIG_RT2X00 is not set
+
+#
+# Enable WiMAX (Networking options) to see the WiMAX drivers
+#
+# CONFIG_WAN is not set
+CONFIG_ATM_DRIVERS=y
+# CONFIG_ATM_DUMMY is not set
+# CONFIG_ATM_TCP is not set
+CONFIG_PPP=m
+CONFIG_PPP_MULTILINK=y
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_ASYNC=m
+# CONFIG_PPP_SYNC_TTY is not set
+# CONFIG_PPP_DEFLATE is not set
+# CONFIG_PPP_BSDCOMP is not set
+# CONFIG_PPP_MPPE is not set
+CONFIG_PPPOE=m
+CONFIG_PPPOATM=m
+# CONFIG_PPPOL2TP is not set
+# CONFIG_SLIP is not set
+CONFIG_SLHC=m
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+# CONFIG_INPUT is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+# CONFIG_DEVKMEM is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=2
+CONFIG_SERIAL_8250_RUNTIME_UARTS=2
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_IPMI_HANDLER is not set
+CONFIG_HW_RANDOM=y
+# CONFIG_HW_RANDOM_TIMERIOMEM is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+# CONFIG_I2C is not set
+# CONFIG_SPI is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+# CONFIG_THERMAL is not set
+# CONFIG_THERMAL_HWMON is not set
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+CONFIG_AR7_WDT=y
+CONFIG_SSB_POSSIBLE=y
+
+#
+# Sonics Silicon Backplane
+#
+CONFIG_SSB=y
+# CONFIG_SSB_SILENT is not set
+# CONFIG_SSB_DEBUG is not set
+CONFIG_SSB_SERIAL=y
+CONFIG_SSB_DRIVER_MIPS=y
+CONFIG_SSB_EMBEDDED=y
+CONFIG_SSB_DRIVER_EXTIF=y
+
+#
+# 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_REGULATOR is not set
+# CONFIG_MEDIA_SUPPORT is not set
+
+#
+# Graphics support
+#
+# 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
+# CONFIG_SOUND is not set
+# CONFIG_USB_SUPPORT is not set
+# CONFIG_MMC is not set
+# CONFIG_MEMSTICK is not set
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+
+#
+# LED drivers
+#
+# CONFIG_LEDS_GPIO is not set
+
+#
+# LED Triggers
+#
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_TIMER=y
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+# CONFIG_LEDS_TRIGGER_BACKLIGHT is not set
+CONFIG_LEDS_TRIGGER_DEFAULT_ON=y
+
+#
+# iptables trigger is under Netfilter config (LED target)
+#
+# CONFIG_ACCESSIBILITY is not set
+CONFIG_RTC_LIB=y
+# CONFIG_RTC_CLASS is not set
+# CONFIG_DMADEVICES is not set
+# CONFIG_AUXDISPLAY is not set
+# CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
+CONFIG_VLYNQ=y
+# CONFIG_STAGING is not set
+
+#
+# File systems
+#
+# CONFIG_EXT2_FS is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_EXT4_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_BTRFS_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
+# CONFIG_DNOTIFY is not set
+# CONFIG_INOTIFY is not set
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
+# CONFIG_PROC_PAGE_MONITOR is not set
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+# 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_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_FS_WBUF_VERIFY is not set
+CONFIG_JFFS2_SUMMARY=y
+# CONFIG_JFFS2_FS_XATTR is not set
+CONFIG_JFFS2_COMPRESSION_OPTIONS=y
+CONFIG_JFFS2_ZLIB=y
+# CONFIG_JFFS2_LZO is not set
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+# CONFIG_JFFS2_CMODE_NONE is not set
+CONFIG_JFFS2_CMODE_PRIORITY=y
+# CONFIG_JFFS2_CMODE_SIZE is not set
+# CONFIG_JFFS2_CMODE_FAVOURLZO is not set
+# CONFIG_CRAMFS is not set
+CONFIG_SQUASHFS=y
+# CONFIG_SQUASHFS_EMBEDDED is not set
+CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE=3
+# 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_NILFS2_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+# CONFIG_NFS_FS is not set
+# CONFIG_NFSD is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS 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=y
+# 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 is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+# CONFIG_SYSV68_PARTITION is not set
+# CONFIG_NLS is not set
+# CONFIG_DLM is not set
+
+#
+# Kernel hacking
+#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+# CONFIG_ENABLE_MUST_CHECK is not set
+CONFIG_FRAME_WARN=1024
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+CONFIG_DEBUG_FS=y
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_DEBUG_MEMORY_INIT is not set
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+CONFIG_SYSCTL_SYSCALL_CHECK=y
+CONFIG_TRACING_SUPPORT=y
+# CONFIG_FTRACE is not set
+# CONFIG_DYNAMIC_DEBUG is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+CONFIG_CMDLINE="rootfstype=squashfs,jffs2"
+
+#
+# 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=m
+CONFIG_CRYPTO_ALGAPI2=m
+CONFIG_CRYPTO_AEAD2=m
+CONFIG_CRYPTO_BLKCIPHER=m
+CONFIG_CRYPTO_BLKCIPHER2=m
+CONFIG_CRYPTO_HASH2=m
+CONFIG_CRYPTO_RNG2=m
+CONFIG_CRYPTO_PCOMP=m
+CONFIG_CRYPTO_MANAGER=m
+CONFIG_CRYPTO_MANAGER2=m
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_NULL is not set
+CONFIG_CRYPTO_WORKQUEUE=m
+# 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 is not set
+# 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 is not set
+# 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 is not set
+# 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=m
+# CONFIG_CRYPTO_ANUBIS is not set
+CONFIG_CRYPTO_ARC4=m
+# 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 is not set
+# 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_ZLIB is not set
+# CONFIG_CRYPTO_LZO is not set
+
+#
+# Random Number Generation
+#
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+# CONFIG_CRYPTO_HW is not set
+# CONFIG_BINARY_PRINTF is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_GENERIC_FIND_LAST_BIT=y
+CONFIG_CRC_CCITT=m
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_T10DIF is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_DECOMPRESS_GZIP=y
+CONFIG_DECOMPRESS_LZMA=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+CONFIG_NLATTR=y
index 5ec1c2f..6f9d085 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  Registration of WRPPMC UART platform device.
  *
- *  Copyright (C) 2007  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *  Copyright (C) 2007  Yoichi Yuasa <yuasa@linux-mips.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
diff --git a/arch/mips/include/asm/amon.h b/arch/mips/include/asm/amon.h
new file mode 100644 (file)
index 0000000..c3dc1a6
--- /dev/null
@@ -0,0 +1,7 @@
+/*
+ * Amon support
+ */
+
+int amon_cpu_avail(int);
+void amon_cpu_start(int, unsigned long, unsigned long,
+                   unsigned long, unsigned long);
index ba1702e..3af0b8f 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  DS1287 timer functions.
  *
- *  Copyright (C) 2008  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *  Copyright (C) 2008  Yoichi Yuasa <yuasa@linux-mips.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
index d58f128..7990694 100644 (file)
@@ -316,9 +316,13 @@ extern void elf_dump_regs(elf_greg_t *, struct pt_regs *regs);
 extern int dump_task_regs(struct task_struct *, elf_gregset_t *);
 extern int dump_task_fpu(struct task_struct *, elf_fpregset_t *);
 
+#ifndef ELF_CORE_COPY_REGS
 #define ELF_CORE_COPY_REGS(elf_regs, regs)                     \
        elf_dump_regs((elf_greg_t *)&(elf_regs), regs);
+#endif
+#ifndef ELF_CORE_COPY_TASK_REGS
 #define ELF_CORE_COPY_TASK_REGS(tsk, elf_regs) dump_task_regs(tsk, elf_regs)
+#endif
 #define ELF_CORE_COPY_FPREGS(tsk, elf_fpregs)                  \
        dump_task_fpu(tsk, elf_fpregs)
 
index d74a8a4..36fd969 100644 (file)
 #define GCMP_CCB_DINTGROUP_OFS         0x0030          /* DINT Group Participate */
 #define GCMP_CCB_DBGGROUP_OFS          0x0100          /* DebugBreak Group */
 
+extern int __init gcmp_probe(unsigned long, unsigned long);
+
 #endif /* _ASM_GCMPREGS_H */
index 954807d..10292e3 100644 (file)
 #define GIC_TRIG_EDGE                  1
 #define GIC_TRIG_LEVEL                 0
 
+#if CONFIG_SMP
+#define GIC_NUM_INTRS                  (24 + NR_CPUS * 2)
+#else
 #define GIC_NUM_INTRS                  32
+#endif
 
 #define MSK(n) ((1 << (n)) - 1)
 #define REG32(addr)            (*(volatile unsigned int *) (addr))
@@ -483,5 +487,7 @@ extern void gic_init(unsigned long gic_base_addr,
 
 extern unsigned int gic_get_int(void);
 extern void gic_send_ipi(unsigned int intr);
+extern unsigned int plat_ipi_call_int_xlate(unsigned int);
+extern unsigned int plat_ipi_resched_int_xlate(unsigned int);
 
 #endif /* _ASM_GICREGS_H */
index f9a7c3a..250a240 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  Galileo/Marvell GT641xx IRQ definitions.
  *
- *  Copyright (C) 2007  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *  Copyright (C) 2007  Yoichi Yuasa <yuasa@linux-mips.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
diff --git a/arch/mips/include/asm/mach-ar7/ar7.h b/arch/mips/include/asm/mach-ar7/ar7.h
new file mode 100644 (file)
index 0000000..de71694
--- /dev/null
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 2006,2007 Felix Fietkau <nbd@openwrt.org>
+ * Copyright (C) 2006,2007 Eugene Konev <ejka@openwrt.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 program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef __AR7_H__
+#define __AR7_H__
+
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/errno.h>
+
+#include <asm/addrspace.h>
+
+#define AR7_SDRAM_BASE 0x14000000
+
+#define AR7_REGS_BASE  0x08610000
+
+#define AR7_REGS_MAC0  (AR7_REGS_BASE + 0x0000)
+#define AR7_REGS_GPIO  (AR7_REGS_BASE + 0x0900)
+/* 0x08610A00 - 0x08610BFF (512 bytes, 128 bytes / clock) */
+#define AR7_REGS_POWER (AR7_REGS_BASE + 0x0a00)
+#define AR7_REGS_CLOCKS (AR7_REGS_POWER + 0x80)
+#define UR8_REGS_CLOCKS (AR7_REGS_POWER + 0x20)
+#define AR7_REGS_UART0 (AR7_REGS_BASE + 0x0e00)
+#define AR7_REGS_USB   (AR7_REGS_BASE + 0x1200)
+#define AR7_REGS_RESET (AR7_REGS_BASE + 0x1600)
+#define AR7_REGS_VLYNQ0        (AR7_REGS_BASE + 0x1800)
+#define AR7_REGS_DCL   (AR7_REGS_BASE + 0x1a00)
+#define AR7_REGS_VLYNQ1        (AR7_REGS_BASE + 0x1c00)
+#define AR7_REGS_MDIO  (AR7_REGS_BASE + 0x1e00)
+#define AR7_REGS_IRQ   (AR7_REGS_BASE + 0x2400)
+#define AR7_REGS_MAC1  (AR7_REGS_BASE + 0x2800)
+
+#define AR7_REGS_WDT   (AR7_REGS_BASE + 0x1f00)
+#define UR8_REGS_WDT   (AR7_REGS_BASE + 0x0b00)
+#define UR8_REGS_UART1 (AR7_REGS_BASE + 0x0f00)
+
+#define AR7_RESET_PEREPHERIAL  0x0
+#define AR7_RESET_SOFTWARE     0x4
+#define AR7_RESET_STATUS       0x8
+
+#define AR7_RESET_BIT_CPMAC_LO 17
+#define AR7_RESET_BIT_CPMAC_HI 21
+#define AR7_RESET_BIT_MDIO     22
+#define AR7_RESET_BIT_EPHY     26
+
+/* GPIO control registers */
+#define AR7_GPIO_INPUT 0x0
+#define AR7_GPIO_OUTPUT        0x4
+#define AR7_GPIO_DIR   0x8
+#define AR7_GPIO_ENABLE        0xc
+
+#define AR7_CHIP_7100  0x18
+#define AR7_CHIP_7200  0x2b
+#define AR7_CHIP_7300  0x05
+
+/* Interrupts */
+#define AR7_IRQ_UART0  15
+#define AR7_IRQ_UART1  16
+
+/* Clocks */
+#define AR7_AFE_CLOCK  35328000
+#define AR7_REF_CLOCK  25000000
+#define AR7_XTAL_CLOCK 24000000
+
+struct plat_cpmac_data {
+       int reset_bit;
+       int power_bit;
+       u32 phy_mask;
+       char dev_addr[6];
+};
+
+struct plat_dsl_data {
+       int reset_bit_dsl;
+       int reset_bit_sar;
+};
+
+extern int ar7_cpu_clock, ar7_bus_clock, ar7_dsp_clock;
+
+static inline u16 ar7_chip_id(void)
+{
+       return readl((void *)KSEG1ADDR(AR7_REGS_GPIO + 0x14)) & 0xffff;
+}
+
+static inline u8 ar7_chip_rev(void)
+{
+       return (readl((void *)KSEG1ADDR(AR7_REGS_GPIO + 0x14)) >> 16) & 0xff;
+}
+
+static inline int ar7_cpu_freq(void)
+{
+       return ar7_cpu_clock;
+}
+
+static inline int ar7_bus_freq(void)
+{
+       return ar7_bus_clock;
+}
+
+static inline int ar7_vbus_freq(void)
+{
+       return ar7_bus_clock / 2;
+}
+#define ar7_cpmac_freq ar7_vbus_freq
+
+static inline int ar7_dsp_freq(void)
+{
+       return ar7_dsp_clock;
+}
+
+static inline int ar7_has_high_cpmac(void)
+{
+       u16 chip_id = ar7_chip_id();
+       switch (chip_id) {
+       case AR7_CHIP_7100:
+       case AR7_CHIP_7200:
+               return 0;
+       case AR7_CHIP_7300:
+               return 1;
+       default:
+               return -ENXIO;
+       }
+}
+#define ar7_has_high_vlynq ar7_has_high_cpmac
+#define ar7_has_second_uart ar7_has_high_cpmac
+
+static inline void ar7_device_enable(u32 bit)
+{
+       void *reset_reg =
+               (void *)KSEG1ADDR(AR7_REGS_RESET + AR7_RESET_PEREPHERIAL);
+       writel(readl(reset_reg) | (1 << bit), reset_reg);
+       msleep(20);
+}
+
+static inline void ar7_device_disable(u32 bit)
+{
+       void *reset_reg =
+               (void *)KSEG1ADDR(AR7_REGS_RESET + AR7_RESET_PEREPHERIAL);
+       writel(readl(reset_reg) & ~(1 << bit), reset_reg);
+       msleep(20);
+}
+
+static inline void ar7_device_reset(u32 bit)
+{
+       ar7_device_disable(bit);
+       ar7_device_enable(bit);
+}
+
+static inline void ar7_device_on(u32 bit)
+{
+       void *power_reg = (void *)KSEG1ADDR(AR7_REGS_POWER);
+       writel(readl(power_reg) | (1 << bit), power_reg);
+       msleep(20);
+}
+
+static inline void ar7_device_off(u32 bit)
+{
+       void *power_reg = (void *)KSEG1ADDR(AR7_REGS_POWER);
+       writel(readl(power_reg) & ~(1 << bit), power_reg);
+       msleep(20);
+}
+
+#endif /* __AR7_H__ */
diff --git a/arch/mips/include/asm/mach-ar7/gpio.h b/arch/mips/include/asm/mach-ar7/gpio.h
new file mode 100644 (file)
index 0000000..cbe9c4f
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2007 Florian Fainelli <florian@openwrt.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 program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef __AR7_GPIO_H__
+#define __AR7_GPIO_H__
+
+#include <asm/mach-ar7/ar7.h>
+
+#define AR7_GPIO_MAX 32
+
+extern int gpio_request(unsigned gpio, const char *label);
+extern void gpio_free(unsigned gpio);
+
+/* Common GPIO layer */
+static inline int gpio_get_value(unsigned gpio)
+{
+       void __iomem *gpio_in =
+               (void __iomem *)KSEG1ADDR(AR7_REGS_GPIO + AR7_GPIO_INPUT);
+
+       return readl(gpio_in) & (1 << gpio);
+}
+
+static inline void gpio_set_value(unsigned gpio, int value)
+{
+       void __iomem *gpio_out =
+               (void __iomem *)KSEG1ADDR(AR7_REGS_GPIO + AR7_GPIO_OUTPUT);
+       unsigned tmp;
+
+       tmp = readl(gpio_out) & ~(1 << gpio);
+       if (value)
+               tmp |= 1 << gpio;
+       writel(tmp, gpio_out);
+}
+
+static inline int gpio_direction_input(unsigned gpio)
+{
+       void __iomem *gpio_dir =
+               (void __iomem *)KSEG1ADDR(AR7_REGS_GPIO + AR7_GPIO_DIR);
+
+       if (gpio >= AR7_GPIO_MAX)
+               return -EINVAL;
+
+       writel(readl(gpio_dir) | (1 << gpio), gpio_dir);
+
+       return 0;
+}
+
+static inline int gpio_direction_output(unsigned gpio, int value)
+{
+       void __iomem *gpio_dir =
+               (void __iomem *)KSEG1ADDR(AR7_REGS_GPIO + AR7_GPIO_DIR);
+
+       if (gpio >= AR7_GPIO_MAX)
+               return -EINVAL;
+
+       gpio_set_value(gpio, value);
+       writel(readl(gpio_dir) & ~(1 << gpio), gpio_dir);
+
+       return 0;
+}
+
+static inline int gpio_to_irq(unsigned gpio)
+{
+       return -EINVAL;
+}
+
+static inline int irq_to_gpio(unsigned irq)
+{
+       return -EINVAL;
+}
+
+/* Board specific GPIO functions */
+static inline int ar7_gpio_enable(unsigned gpio)
+{
+       void __iomem *gpio_en =
+               (void __iomem *)KSEG1ADDR(AR7_REGS_GPIO + AR7_GPIO_ENABLE);
+
+       writel(readl(gpio_en) | (1 << gpio), gpio_en);
+
+       return 0;
+}
+
+static inline int ar7_gpio_disable(unsigned gpio)
+{
+       void __iomem *gpio_en =
+               (void __iomem *)KSEG1ADDR(AR7_REGS_GPIO + AR7_GPIO_ENABLE);
+
+       writel(readl(gpio_en) & ~(1 << gpio), gpio_en);
+
+       return 0;
+}
+
+#include <asm-generic/gpio.h>
+
+#endif
diff --git a/arch/mips/include/asm/mach-ar7/irq.h b/arch/mips/include/asm/mach-ar7/irq.h
new file mode 100644 (file)
index 0000000..39e9757
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Shamelessly copied from asm-mips/mach-emma2rh/
+ * Copyright (C) 2003 by Ralf Baechle
+ */
+#ifndef __ASM_AR7_IRQ_H
+#define __ASM_AR7_IRQ_H
+
+#define NR_IRQS        256
+
+#include_next <irq.h>
+
+#endif /* __ASM_AR7_IRQ_H */
diff --git a/arch/mips/include/asm/mach-ar7/prom.h b/arch/mips/include/asm/mach-ar7/prom.h
new file mode 100644 (file)
index 0000000..088f61f
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2006, 2007 Florian Fainelli <florian@openwrt.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 program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef __PROM_H__
+#define __PROM_H__
+
+extern char *prom_getenv(const char *name);
+extern void prom_meminit(void);
+
+#endif /* __PROM_H__ */
diff --git a/arch/mips/include/asm/mach-ar7/spaces.h b/arch/mips/include/asm/mach-ar7/spaces.h
new file mode 100644 (file)
index 0000000..ac28f27
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1994 - 1999, 2000, 03, 04 Ralf Baechle
+ * Copyright (C) 2000, 2002  Maciej W. Rozycki
+ * Copyright (C) 1990, 1999, 2000 Silicon Graphics, Inc.
+ */
+#ifndef _ASM_AR7_SPACES_H
+#define _ASM_AR7_SPACES_H
+
+/*
+ * This handles the memory map.
+ * We handle pages at KSEG0 for kernels with 32 bit address space.
+ */
+#define PAGE_OFFSET            0x94000000UL
+#define PHYS_OFFSET            0x14000000UL
+
+#include <asm/mach-generic/spaces.h>
+
+#endif /* __ASM_AR7_SPACES_H */
diff --git a/arch/mips/include/asm/mach-ar7/war.h b/arch/mips/include/asm/mach-ar7/war.h
new file mode 100644 (file)
index 0000000..f4862b5
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2002, 2004, 2007 by Ralf Baechle <ralf@linux-mips.org>
+ */
+#ifndef __ASM_MIPS_MACH_AR7_WAR_H
+#define __ASM_MIPS_MACH_AR7_WAR_H
+
+#define R4600_V1_INDEX_ICACHEOP_WAR    0
+#define R4600_V1_HIT_CACHEOP_WAR       0
+#define R4600_V2_HIT_CACHEOP_WAR       0
+#define R5432_CP0_INTERRUPT_WAR                0
+#define BCM1250_M3_WAR                 0
+#define SIBYTE_1956_WAR                        0
+#define MIPS4K_ICACHE_REFILL_WAR       0
+#define MIPS_CACHE_SYNC_WAR            0
+#define TX49XX_ICACHE_INDEX_INV_WAR    0
+#define RM9000_CDEX_SMP_WAR            0
+#define ICACHE_REFILLS_WORKAROUND_WAR  0
+#define R10000_LLSC_WAR                        0
+#define MIPS34K_MISSED_ITLB_WAR                0
+
+#endif /* __ASM_MIPS_MACH_AR7_WAR_H */
index 57c8c9a..9da9acf 100644 (file)
@@ -8,7 +8,7 @@
  * Copyright (C) 1997 Cobalt Microserver
  * Copyright (C) 1997, 2003 Ralf Baechle
  * Copyright (C) 2001-2003 Liam Davies (ldavies@agile.tv)
- * Copyright (C) 2007 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ * Copyright (C) 2007 Yoichi Yuasa <yuasa@linux-mips.org>
  */
 #ifndef _ASM_COBALT_IRQ_H
 #define _ASM_COBALT_IRQ_H
index ae9c552..f8afec3 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  Copyright (C) 2006  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *  Copyright (C) 2006  Yoichi Yuasa <yuasa@linux-mips.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
similarity index 52%
rename from arch/mips/cavium-octeon/pci-common.h
rename to arch/mips/include/asm/octeon/pci-octeon.h
index 74ae799..6ac5d3e 100644 (file)
@@ -3,23 +3,29 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 2005-2007 Cavium Networks
+ * Copyright (C) 2005-2009 Cavium Networks
  */
-#ifndef __OCTEON_PCI_COMMON_H__
-#define __OCTEON_PCI_COMMON_H__
+
+#ifndef __PCI_OCTEON_H__
+#define __PCI_OCTEON_H__
 
 #include <linux/pci.h>
 
 /* Some PCI cards require delays when accessing config space. */
 #define PCI_CONFIG_SPACE_DELAY 10000
 
-/* pcibios_map_irq() is defined inside pci-common.c. All it does is call the
-   Octeon specific version pointed to by this variable. This function needs to
-   change for PCI or PCIe based hosts */
-extern typeof(pcibios_map_irq) *octeon_pcibios_map_irq;
+/*
+ * pcibios_map_irq() is defined inside pci-octeon.c. All it does is
+ * call the Octeon specific version pointed to by this variable. This
+ * function needs to change for PCI or PCIe based hosts.
+ */
+extern int (*octeon_pcibios_map_irq)(const struct pci_dev *dev,
+                                    u8 slot, u8 pin);
 
-/* The following defines are only used when octeon_dma_bar_type =
-   OCTEON_DMA_BAR_TYPE_BIG */
+/*
+ * The following defines are used when octeon_dma_bar_type =
+ * OCTEON_DMA_BAR_TYPE_BIG
+ */
 #define OCTEON_PCI_BAR1_HOLE_BITS 5
 #define OCTEON_PCI_BAR1_HOLE_SIZE (1ul<<(OCTEON_PCI_BAR1_HOLE_BITS+3))
 
@@ -30,9 +36,9 @@ enum octeon_dma_bar_type {
        OCTEON_DMA_BAR_TYPE_PCIE
 };
 
-/**
- * This is a variable to tell the DMA mapping system in dma-octeon.c
- * how to map PCI DMA addresses.
+/*
+ * This tells the DMA mapping system in dma-octeon.c how to map PCI
+ * DMA addresses.
  */
 extern enum octeon_dma_bar_type octeon_dma_bar_type;
 
index dc0eaa7..96a14a4 100644 (file)
@@ -165,7 +165,14 @@ typedef struct { unsigned long pgprot; } pgprot_t;
 
 #ifdef CONFIG_FLATMEM
 
-#define pfn_valid(pfn)         ((pfn) >= ARCH_PFN_OFFSET && (pfn) < max_mapnr)
+#define pfn_valid(pfn)                                                 \
+({                                                                     \
+       unsigned long __pfn = (pfn);                                    \
+       /* avoid <linux/bootmem.h> include hell */                      \
+       extern unsigned long min_low_pfn;                               \
+                                                                       \
+       __pfn >= min_low_pfn && __pfn < max_mapnr;                      \
+})
 
 #elif defined(CONFIG_SPARSEMEM)
 
index 634b55d..910e71a 100644 (file)
@@ -69,7 +69,7 @@
 
 #endif
 
-#ifdef CONFIG_64BIT
+#if defined(CONFIG_64BIT) && !defined(WANT_COMPAT_REG_H)
 
 #define EF_R0                   0
 #define EF_R1                   1
index 99993c0..97c2f81 100644 (file)
@@ -38,7 +38,11 @@ static inline __attribute_const__ __u32 __arch_swab32(__u32 x)
 }
 #define __arch_swab32 __arch_swab32
 
-#ifdef CONFIG_CPU_MIPS64_R2
+/*
+ * Having already checked for CONFIG_CPU_MIPSR2, enable the
+ * optimized version for 64-bit kernel on r2 CPUs.
+ */
+#ifdef CONFIG_64BIT
 static inline __attribute_const__ __u64 __arch_swab64(__u64 x)
 {
        __asm__(
@@ -50,6 +54,6 @@ static inline __attribute_const__ __u64 __arch_swab64(__u64 x)
        return x;
 }
 #define __arch_swab64 __arch_swab64
-#endif /* CONFIG_CPU_MIPS64_R2 */
+#endif /* CONFIG_64BIT */
 #endif /* CONFIG_CPU_MIPSR2 */
 #endif /* _ASM_SWAB_H */
index 4000501..b70c49f 100644 (file)
 #define __NR_inotify_init1             (__NR_Linux + 329)
 #define __NR_preadv                    (__NR_Linux + 330)
 #define __NR_pwritev                   (__NR_Linux + 331)
+#define __NR_rt_tgsigqueueinfo         (__NR_Linux + 332)
+#define __NR_perf_counter_open         (__NR_Linux + 333)
 
 /*
  * Offset of the last Linux o32 flavoured syscall
  */
-#define __NR_Linux_syscalls            331
+#define __NR_Linux_syscalls            333
 
 #endif /* _MIPS_SIM == _MIPS_SIM_ABI32 */
 
 #define __NR_O32_Linux                 4000
-#define __NR_O32_Linux_syscalls                331
+#define __NR_O32_Linux_syscalls                333
 
 #if _MIPS_SIM == _MIPS_SIM_ABI64
 
 #define __NR_inotify_init1             (__NR_Linux + 288)
 #define __NR_preadv                    (__NR_Linux + 289)
 #define __NR_pwritev                   (__NR_Linux + 290)
+#define __NR_rt_tgsigqueueinfo         (__NR_Linux + 291)
+#define __NR_perf_counter_open         (__NR_Linux + 292)
 
 /*
  * Offset of the last Linux 64-bit flavoured syscall
  */
-#define __NR_Linux_syscalls            290
+#define __NR_Linux_syscalls            292
 
 #endif /* _MIPS_SIM == _MIPS_SIM_ABI64 */
 
 #define __NR_64_Linux                  5000
-#define __NR_64_Linux_syscalls         290
+#define __NR_64_Linux_syscalls         292
 
 #if _MIPS_SIM == _MIPS_SIM_NABI32
 
 #define __NR_inotify_init1             (__NR_Linux + 292)
 #define __NR_preadv                    (__NR_Linux + 293)
 #define __NR_pwritev                   (__NR_Linux + 294)
+#define __NR_rt_tgsigqueueinfo         (__NR_Linux + 295)
+#define __NR_perf_counter_open         (__NR_Linux + 296)
 
 /*
  * Offset of the last N32 flavoured syscall
  */
-#define __NR_Linux_syscalls            294
+#define __NR_Linux_syscalls            296
 
 #endif /* _MIPS_SIM == _MIPS_SIM_NABI32 */
 
 #define __NR_N32_Linux                 6000
-#define __NR_N32_Linux_syscalls                294
+#define __NR_N32_Linux_syscalls                296
 
 #ifdef __KERNEL__
 
index e0ee05a..fcc6569 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  capcella.h, Include file for ZAO Networks Capcella.
  *
- *  Copyright (C) 2002-2004  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *  Copyright (C) 2002-2004  Yoichi Yuasa <yuasa@linux-mips.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
index 0bcdd3a..6a90bc1 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  Include file for NEC VR4100 series General-purpose I/O Unit.
  *
- *  Copyright (C) 2005  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *  Copyright (C) 2005-2009  Yoichi Yuasa <yuasa@linux-mips.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
@@ -41,7 +41,8 @@ typedef enum {
        IRQ_SIGNAL_HOLD,
 } irq_signal_t;
 
-extern void vr41xx_set_irq_trigger(unsigned int pin, irq_trigger_t trigger, irq_signal_t signal);
+extern void vr41xx_set_irq_trigger(unsigned int pin, irq_trigger_t trigger,
+                                  irq_signal_t signal);
 
 typedef enum {
        IRQ_LEVEL_LOW,
@@ -51,23 +52,6 @@ typedef enum {
 extern void vr41xx_set_irq_level(unsigned int pin, irq_level_t level);
 
 typedef enum {
-       GPIO_DATA_LOW,
-       GPIO_DATA_HIGH,
-       GPIO_DATA_INVAL,
-} gpio_data_t;
-
-extern gpio_data_t vr41xx_gpio_get_pin(unsigned int pin);
-extern int vr41xx_gpio_set_pin(unsigned int pin, gpio_data_t data);
-
-typedef enum {
-       GPIO_INPUT,
-       GPIO_OUTPUT,
-       GPIO_OUTPUT_DISABLE,
-} gpio_direction_t;
-
-extern int vr41xx_gpio_set_direction(unsigned int pin, gpio_direction_t dir);
-
-typedef enum {
        GPIO_PULL_DOWN,
        GPIO_PULL_UP,
        GPIO_PULL_DISABLE,
index d315dfb..b07f732 100644 (file)
@@ -7,7 +7,7 @@
  * Copyright (C) 2001, 2002 Paul Mundt
  * Copyright (C) 2002 MontaVista Software, Inc.
  * Copyright (C) 2002 TimeSys Corp.
- * Copyright (C) 2003-2006 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ * Copyright (C) 2003-2006 Yoichi Yuasa <yuasa@linux-mips.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
index 1d67df8..130d09d 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  mpc30x.h, Include file for Victor MP-C303/304.
  *
- *  Copyright (C) 2002-2004  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *  Copyright (C) 2002-2004  Yoichi Yuasa <yuasa@linux-mips.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
index 6fc01ce..c231a3d 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  Include file for NEC VR4100 series PCI Control Unit.
  *
- *  Copyright (C) 2004-2005  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *  Copyright (C) 2004-2005  Yoichi Yuasa <yuasa@linux-mips.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
index da9f6e3..ca806bc 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  Include file for NEC VR4100 series Serial Interface Unit.
  *
- *  Copyright (C) 2005-2008  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *  Copyright (C) 2005-2008  Yoichi Yuasa <yuasa@linux-mips.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
index dc981b4..c78e824 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  tb0219.h, Include file for TANBAC TB0219.
  *
- *  Copyright (C) 2002-2004  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *  Copyright (C) 2002-2004  Yoichi Yuasa <yuasa@linux-mips.org>
  *
  *  Modified for TANBAC TB0219:
  *  Copyright (C) 2003 Megasolution Inc.  <matsu@megasolution.jp>
index de527dc..36f5f79 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  tb0226.h, Include file for TANBAC TB0226.
  *
- *  Copyright (C) 2002-2004  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *  Copyright (C) 2002-2004  Yoichi Yuasa <yuasa@linux-mips.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
index 22be649..7b96a43 100644 (file)
@@ -7,7 +7,7 @@
  * Copyright (C) 2001, 2002 Paul Mundt
  * Copyright (C) 2002 MontaVista Software, Inc.
  * Copyright (C) 2002 TimeSys Corp.
- * Copyright (C) 2003-2008 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ * Copyright (C) 2003-2008 Yoichi Yuasa <yuasa@linux-mips.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
index e1333d7..ff44823 100644 (file)
@@ -53,6 +53,23 @@ typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
 #define ELF_ET_DYN_BASE         (TASK32_SIZE / 3 * 2)
 
 #include <asm/processor.h>
+
+/*
+ * When this file is selected, we are definitely running a 64bit kernel.
+ * So using the right regs define in asm/reg.h
+ */
+#define WANT_COMPAT_REG_H
+
+/* These MUST be defined before elf.h gets included */
+extern void elf32_core_copy_regs(elf_gregset_t grp, struct pt_regs *regs);
+#define ELF_CORE_COPY_REGS(_dest, _regs) elf32_core_copy_regs(_dest, _regs);
+#define ELF_CORE_COPY_TASK_REGS(_tsk, _dest)                           \
+({                                                                     \
+       int __res = 1;                                                  \
+       elf32_core_copy_regs(*(_dest), task_pt_regs(_tsk));             \
+       __res;                                                          \
+})
+
 #include <linux/module.h>
 #include <linux/elfcore.h>
 #include <linux/compat.h>
@@ -110,9 +127,6 @@ jiffies_to_compat_timeval(unsigned long jiffies, struct compat_timeval *value)
        value->tv_usec = rem / NSEC_PER_USEC;
 }
 
-#undef ELF_CORE_COPY_REGS
-#define ELF_CORE_COPY_REGS(_dest, _regs) elf32_core_copy_regs(_dest, _regs);
-
 void elf32_core_copy_regs(elf_gregset_t grp, struct pt_regs *regs)
 {
        int i;
index 1ada45e..6996da4 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  DS1287 clockevent driver
  *
- *  Copyright (C) 2008  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *  Copyright (C) 2008  Yoichi Yuasa <yuasa@linux-mips.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
index e9b787f..92351e0 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  GT641xx clockevent routines.
  *
- *  Copyright (C) 2007  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *  Copyright (C) 2007  Yoichi Yuasa <yuasa@linux-mips.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
index b551f48..23da108 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  DEC I/O ASIC's counter clocksource
  *
- *  Copyright (C) 2008  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *  Copyright (C) 2008  Yoichi Yuasa <yuasa@linux-mips.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
index 39000f1..d2072cd 100644 (file)
@@ -107,9 +107,7 @@ static unsigned int gic_irq_startup(unsigned int irq)
 {
        pr_debug("CPU%d: %s: irq%d\n", smp_processor_id(), __func__, irq);
        irq -= _irqbase;
-       /* FIXME: this is wrong for !GICISWORDLITTLEENDIAN */
-       GICWRITE(GIC_REG_ADDR(SHARED, (GIC_SH_SMASK_31_0_OFS + (irq / 32))),
-                1 << (irq % 32));
+       GIC_SET_INTR_MASK(irq, 1);
        return 0;
 }
 
@@ -120,8 +118,7 @@ static void gic_irq_ack(unsigned int irq)
 #endif
        pr_debug("CPU%d: %s: irq%d\n", smp_processor_id(), __func__, irq);
        irq -= _irqbase;
-       GICWRITE(GIC_REG_ADDR(SHARED, (GIC_SH_RMASK_31_0_OFS + (irq / 32))),
-                1 << (irq % 32));
+       GIC_CLR_INTR_MASK(irq, 1);
 
        if (_intrmap[irq].trigtype == GIC_TRIG_EDGE) {
                if (!gic_wedgeb2bok)
@@ -138,18 +135,14 @@ static void gic_mask_irq(unsigned int irq)
 {
        pr_debug("CPU%d: %s: irq%d\n", smp_processor_id(), __func__, irq);
        irq -= _irqbase;
-       /* FIXME: this is wrong for !GICISWORDLITTLEENDIAN */
-       GICWRITE(GIC_REG_ADDR(SHARED, (GIC_SH_RMASK_31_0_OFS + (irq / 32))),
-                1 << (irq % 32));
+       GIC_CLR_INTR_MASK(irq, 1);
 }
 
 static void gic_unmask_irq(unsigned int irq)
 {
        pr_debug("CPU%d: %s: irq%d\n", smp_processor_id(), __func__, irq);
        irq -= _irqbase;
-       /* FIXME: this is wrong for !GICISWORDLITTLEENDIAN */
-       GICWRITE(GIC_REG_ADDR(SHARED, (GIC_SH_SMASK_31_0_OFS + (irq / 32))),
-                1 << (irq % 32));
+       GIC_SET_INTR_MASK(irq, 1);
 }
 
 #ifdef CONFIG_SMP
@@ -254,6 +247,10 @@ static void __init gic_basic_init(void)
                if (cpu == X)
                        continue;
 
+               if (cpu == 0 && i != 0 && _intrmap[i].intrnum == 0 &&
+                                       _intrmap[i].ipiflag == 0)
+                       continue;
+
                setup_intr(_intrmap[i].intrnum,
                                _intrmap[i].cpunum,
                                _intrmap[i].pin,
index 1b81b13..ebcc5f7 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  GT641xx IRQ routines.
  *
- *  Copyright (C) 2007  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *  Copyright (C) 2007  Yoichi Yuasa <yuasa@linux-mips.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
index 0b31b9b..20a86e0 100644 (file)
@@ -652,6 +652,8 @@ einval:     li      v0, -ENOSYS
        sys     sys_inotify_init1       1
        sys     sys_preadv              6       /* 4330 */
        sys     sys_pwritev             6
+       sys     sys_rt_tgsigqueueinfo   4
+       sys     sys_perf_counter_open   5
        .endm
 
        /* We pre-compute the number of _instruction_ bytes needed to
index c647fd6..b046130 100644 (file)
@@ -489,4 +489,6 @@ sys_call_table:
        PTR     sys_inotify_init1
        PTR     sys_preadv
        PTR     sys_pwritev                     /* 5390 */
+       PTR     sys_rt_tgsigqueueinfo
+       PTR     sys_perf_counter_open
        .size   sys_call_table,.-sys_call_table
index 93cc672..7c4a94f 100644 (file)
@@ -164,7 +164,7 @@ EXPORT(sysn32_call_table)
        PTR     sys_connect
        PTR     sys_accept
        PTR     sys_sendto
-       PTR     sys_recvfrom
+       PTR     compat_sys_recvfrom
        PTR     compat_sys_sendmsg              /* 6045 */
        PTR     compat_sys_recvmsg
        PTR     sys_shutdown
@@ -415,4 +415,6 @@ EXPORT(sysn32_call_table)
        PTR     sys_inotify_init1
        PTR     sys_preadv
        PTR     sys_pwritev
+       PTR     compat_sys_rt_tgsigqueueinfo    /* 5295 */
+       PTR     sys_perf_counter_open
        .size   sysn32_call_table,.-sysn32_call_table
index a5598b2..821fc97 100644 (file)
@@ -378,8 +378,8 @@ sys_call_table:
        PTR     sys_getsockname
        PTR     sys_getsockopt
        PTR     sys_listen
-       PTR     sys_recv                        /* 4175 */
-       PTR     sys_recvfrom
+       PTR     compat_sys_recv                 /* 4175 */
+       PTR     compat_sys_recvfrom
        PTR     compat_sys_recvmsg
        PTR     sys_send
        PTR     compat_sys_sendmsg
@@ -535,4 +535,6 @@ sys_call_table:
        PTR     sys_inotify_init1
        PTR     compat_sys_preadv               /* 4330 */
        PTR     compat_sys_pwritev
+       PTR     compat_sys_rt_tgsigqueueinfo
+       PTR     sys_perf_counter_open
        .size   sys_call_table,.-sys_call_table
index 653be06..ad0ff5d 100644 (file)
 #include <asm/mipsregs.h>
 #include <asm/mipsmtregs.h>
 #include <asm/mips_mt.h>
-
-/*
- * Crude manipulation of the CPU masks to control which
- * which CPU's are brought online during initialisation
- *
- * Beware... this needs to be called after CPU discovery
- * but before CPU bringup
- */
-static int __init allowcpus(char *str)
-{
-       cpumask_t cpu_allow_map;
-       char buf[256];
-       int len;
-
-       cpus_clear(cpu_allow_map);
-       if (cpulist_parse(str, &cpu_allow_map) == 0) {
-               cpu_set(0, cpu_allow_map);
-               cpus_and(cpu_possible_map, cpu_possible_map, cpu_allow_map);
-               len = cpulist_scnprintf(buf, sizeof(buf)-1, &cpu_possible_map);
-               buf[len] = '\0';
-               pr_debug("Allowable CPUs: %s\n", buf);
-               return 1;
-       } else
-               return 0;
-}
-__setup("allowcpus=", allowcpus);
+#include <asm/amon.h>
+#include <asm/gic.h>
 
 static void ipi_call_function(unsigned int cpu)
 {
-       unsigned int action = 0;
-
        pr_debug("CPU%d: %s cpu %d status %08x\n",
                 smp_processor_id(), __func__, cpu, read_c0_status());
 
-       switch (cpu) {
-       case 0:
-               action = GIC_IPI_EXT_INTR_CALLFNC_VPE0;
-               break;
-       case 1:
-               action = GIC_IPI_EXT_INTR_CALLFNC_VPE1;
-               break;
-       case 2:
-               action = GIC_IPI_EXT_INTR_CALLFNC_VPE2;
-               break;
-       case 3:
-               action = GIC_IPI_EXT_INTR_CALLFNC_VPE3;
-               break;
-       }
-       gic_send_ipi(action);
+       gic_send_ipi(plat_ipi_call_int_xlate(cpu));
 }
 
 
 static void ipi_resched(unsigned int cpu)
 {
-       unsigned int action = 0;
-
        pr_debug("CPU%d: %s cpu %d status %08x\n",
                 smp_processor_id(), __func__, cpu, read_c0_status());
 
-       switch (cpu) {
-       case 0:
-               action = GIC_IPI_EXT_INTR_RESCHED_VPE0;
-               break;
-       case 1:
-               action = GIC_IPI_EXT_INTR_RESCHED_VPE1;
-               break;
-       case 2:
-               action = GIC_IPI_EXT_INTR_RESCHED_VPE2;
-               break;
-       case 3:
-               action = GIC_IPI_EXT_INTR_RESCHED_VPE3;
-               break;
-       }
-       gic_send_ipi(action);
+       gic_send_ipi(plat_ipi_resched_int_xlate(cpu));
 }
 
 /*
@@ -206,7 +150,7 @@ static void cmp_boot_secondary(int cpu, struct task_struct *idle)
                           (unsigned long)(gp + sizeof(struct thread_info)));
 #endif
 
-       amon_cpu_start(cpu, pc, sp, gp, a0);
+       amon_cpu_start(cpu, pc, sp, (unsigned long)gp, a0);
 }
 
 /*
index 9021108..05dd170 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Count register synchronisation.
  *
- * All CPUs will have their count registers synchronised to the CPU0 expirelo
+ * All CPUs will have their count registers synchronised to the CPU0 next time
  * value. This can cause a small timewarp for CPU0. All other CPU's should
  * not have done anything significant (but they may have had interrupts
  * enabled briefly - prom_smp_finish() should not be responsible for enabling
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/irqflags.h>
-#include <linux/r4k-timer.h>
+#include <linux/cpumask.h>
 
+#include <asm/r4k-timer.h>
 #include <asm/atomic.h>
 #include <asm/barrier.h>
-#include <asm/cpumask.h>
 #include <asm/mipsregs.h>
 
-static atomic_t __initdata count_start_flag = ATOMIC_INIT(0);
-static atomic_t __initdata count_count_start = ATOMIC_INIT(0);
-static atomic_t __initdata count_count_stop = ATOMIC_INIT(0);
+static atomic_t __cpuinitdata count_start_flag = ATOMIC_INIT(0);
+static atomic_t __cpuinitdata count_count_start = ATOMIC_INIT(0);
+static atomic_t __cpuinitdata count_count_stop = ATOMIC_INIT(0);
+static atomic_t __cpuinitdata count_reference = ATOMIC_INIT(0);
 
 #define COUNTON        100
 #define NR_LOOPS 5
 
-void __init synchronise_count_master(void)
+void __cpuinit synchronise_count_master(void)
 {
        int i;
        unsigned long flags;
@@ -42,19 +43,20 @@ void __init synchronise_count_master(void)
        return;
 #endif
 
-       pr_info("Checking COUNT synchronization across %u CPUs: ",
-               num_online_cpus());
+       printk(KERN_INFO "Synchronize counters across %u CPUs: ",
+              num_online_cpus());
 
        local_irq_save(flags);
 
        /*
         * Notify the slaves that it's time to start
         */
+       atomic_set(&count_reference, read_c0_count());
        atomic_set(&count_start_flag, 1);
        smp_wmb();
 
-       /* Count will be initialised to expirelo for all CPU's */
-       initcount = expirelo;
+       /* Count will be initialised to current timer for all CPU's */
+       initcount = read_c0_count();
 
        /*
         * We loop a few times to get a primed instruction cache,
@@ -106,7 +108,7 @@ void __init synchronise_count_master(void)
        printk("done.\n");
 }
 
-void __init synchronise_count_slave(void)
+void __cpuinit synchronise_count_slave(void)
 {
        int i;
        unsigned long flags;
@@ -131,8 +133,8 @@ void __init synchronise_count_slave(void)
        while (!atomic_read(&count_start_flag))
                mb();
 
-       /* Count will be initialised to expirelo for all CPU's */
-       initcount = expirelo;
+       /* Count will be initialised to next expire for all CPU's */
+       initcount = atomic_read(&count_reference);
 
        ncpus = num_online_cpus();
        for (i = 0; i < NR_LOOPS; i++) {
@@ -156,4 +158,3 @@ void __init synchronise_count_slave(void)
        local_irq_restore(flags);
 }
 #undef NR_LOOPS
-#endif
index 3ca5f42..07b9ec2 100644 (file)
@@ -1387,7 +1387,7 @@ static ssize_t store_ntcs(struct device *dev, struct device_attribute *attr,
        return len;
 
 out_einval:
-       return -EINVAL;;
+       return -EINVAL;
 }
 
 static struct device_attribute vpe_class_attributes[] = {
index 475038a..27c807b 100644 (file)
@@ -30,6 +30,7 @@
 #include <asm/cacheflush.h>
 #include <asm/traps.h>
 
+#include <asm/gcmpregs.h>
 #include <asm/mips-boards/prom.h>
 #include <asm/mips-boards/generic.h>
 #include <asm/mips-boards/bonito64.h>
@@ -192,6 +193,8 @@ extern struct plat_smp_ops msmtc_smp_ops;
 
 void __init prom_init(void)
 {
+       int result;
+
        prom_argc = fw_arg0;
        _prom_argv = (int *) fw_arg1;
        _prom_envp = (int *) fw_arg2;
@@ -358,12 +361,21 @@ void __init prom_init(void)
 #ifdef CONFIG_SERIAL_8250_CONSOLE
        console_config();
 #endif
+       /* Early detection of CMP support */
+       result = gcmp_probe(GCMP_BASE_ADDR, GCMP_ADDRSPACE_SZ);
+
 #ifdef CONFIG_MIPS_CMP
-       register_smp_ops(&cmp_smp_ops);
+       if (result)
+               register_smp_ops(&cmp_smp_ops);
 #endif
 #ifdef CONFIG_MIPS_MT_SMP
+#ifdef CONFIG_MIPS_CMP
+       if (!result)
+               register_smp_ops(&vsmp_smp_ops);
+#else
        register_smp_ops(&vsmp_smp_ops);
 #endif
+#endif
 #ifdef CONFIG_MIPS_MT_SMTC
        register_smp_ops(&msmtc_smp_ops);
 #endif
index b4eaf13..a8756f8 100644 (file)
@@ -331,6 +331,21 @@ static struct irqaction irq_call = {
        .flags          = IRQF_DISABLED|IRQF_PERCPU,
        .name           = "IPI_call"
 };
+
+static int gic_resched_int_base;
+static int gic_call_int_base;
+#define GIC_RESCHED_INT(cpu) (gic_resched_int_base+(cpu))
+#define GIC_CALL_INT(cpu) (gic_call_int_base+(cpu))
+
+unsigned int plat_ipi_call_int_xlate(unsigned int cpu)
+{
+       return GIC_CALL_INT(cpu);
+}
+
+unsigned int plat_ipi_resched_int_xlate(unsigned int cpu)
+{
+       return GIC_RESCHED_INT(cpu);
+}
 #endif /* CONFIG_MIPS_MT_SMP */
 
 static struct irqaction i8259irq = {
@@ -370,7 +385,7 @@ static int __initdata msc_nr_eicirqs = ARRAY_SIZE(msc_eicirqmap);
  * Interrupts and CPUs/Core Interrupts. The nature of the External
  * Interrupts is also defined here - polarity/trigger.
  */
-static struct gic_intr_map gic_intr_map[] = {
+static struct gic_intr_map gic_intr_map[GIC_NUM_INTRS] = {
        { GIC_EXT_INTR(0),      X,      X,              X,              X,              0 },
        { GIC_EXT_INTR(1),      X,      X,              X,              X,              0 },
        { GIC_EXT_INTR(2),      X,      X,              X,              X,              0 },
@@ -387,21 +402,14 @@ static struct gic_intr_map gic_intr_map[] = {
        { GIC_EXT_INTR(13),     0,      GIC_MAP_TO_NMI_MSK,     GIC_POL_POS, GIC_TRIG_LEVEL,    0 },
        { GIC_EXT_INTR(14),     0,      GIC_MAP_TO_NMI_MSK,     GIC_POL_POS, GIC_TRIG_LEVEL,    0 },
        { GIC_EXT_INTR(15),     X,      X,              X,              X,              0 },
-       { GIC_EXT_INTR(16),     0,      GIC_CPU_INT1,   GIC_POL_POS, GIC_TRIG_EDGE,     1 },
-       { GIC_EXT_INTR(17),     0,      GIC_CPU_INT2,   GIC_POL_POS, GIC_TRIG_EDGE,     1 },
-       { GIC_EXT_INTR(18),     1,      GIC_CPU_INT1,   GIC_POL_POS, GIC_TRIG_EDGE,     1 },
-       { GIC_EXT_INTR(19),     1,      GIC_CPU_INT2,   GIC_POL_POS, GIC_TRIG_EDGE,     1 },
-       { GIC_EXT_INTR(20),     2,      GIC_CPU_INT1,   GIC_POL_POS, GIC_TRIG_EDGE,     1 },
-       { GIC_EXT_INTR(21),     2,      GIC_CPU_INT2,   GIC_POL_POS, GIC_TRIG_EDGE,     1 },
-       { GIC_EXT_INTR(22),     3,      GIC_CPU_INT1,   GIC_POL_POS, GIC_TRIG_EDGE,     1 },
-       { GIC_EXT_INTR(23),     3,      GIC_CPU_INT2,   GIC_POL_POS, GIC_TRIG_EDGE,     1 },
+/* This is the end of the general interrupts now we do IPI ones */
 };
 #endif
 
 /*
  * GCMP needs to be detected before any SMP initialisation
  */
-static int __init gcmp_probe(unsigned long addr, unsigned long size)
+int __init gcmp_probe(unsigned long addr, unsigned long size)
 {
        if (gcmp_present >= 0)
                return gcmp_present;
@@ -416,28 +424,36 @@ static int __init gcmp_probe(unsigned long addr, unsigned long size)
 }
 
 #if defined(CONFIG_MIPS_MT_SMP)
+static void __init fill_ipi_map1(int baseintr, int cpu, int cpupin)
+{
+       int intr = baseintr + cpu;
+       gic_intr_map[intr].intrnum = GIC_EXT_INTR(intr);
+       gic_intr_map[intr].cpunum = cpu;
+       gic_intr_map[intr].pin = cpupin;
+       gic_intr_map[intr].polarity = GIC_POL_POS;
+       gic_intr_map[intr].trigtype = GIC_TRIG_EDGE;
+       gic_intr_map[intr].ipiflag = 1;
+       ipi_map[cpu] |= (1 << (cpupin + 2));
+}
+
 static void __init fill_ipi_map(void)
 {
-       int i;
+       int cpu;
 
-       for (i = 0; i < ARRAY_SIZE(gic_intr_map); i++) {
-               if (gic_intr_map[i].ipiflag && (gic_intr_map[i].cpunum != X))
-                       ipi_map[gic_intr_map[i].cpunum] |=
-                               (1 << (gic_intr_map[i].pin + 2));
+       for (cpu = 0; cpu < NR_CPUS; cpu++) {
+               fill_ipi_map1(gic_resched_int_base, cpu, GIC_CPU_INT1);
+               fill_ipi_map1(gic_call_int_base, cpu, GIC_CPU_INT2);
        }
 }
 #endif
 
 void __init arch_init_irq(void)
 {
-       int gic_present, gcmp_present;
-
        init_i8259_irqs();
 
        if (!cpu_has_veic)
                mips_cpu_irq_init();
 
-       gcmp_present = gcmp_probe(GCMP_BASE_ADDR, GCMP_ADDRSPACE_SZ);
        if (gcmp_present)  {
                GCMPGCB(GICBA) = GIC_BASE_ADDR | GCMP_GCB_GICBA_EN_MSK;
                gic_present = 1;
@@ -514,24 +530,10 @@ void __init arch_init_irq(void)
        if (gic_present) {
                /* FIXME */
                int i;
-               struct {
-                       unsigned int resched;
-                       unsigned int call;
-               } ipiirq[] = {
-                       {
-                               .resched = GIC_IPI_EXT_INTR_RESCHED_VPE0,
-                               .call =  GIC_IPI_EXT_INTR_CALLFNC_VPE0},
-                       {
-                               .resched = GIC_IPI_EXT_INTR_RESCHED_VPE1,
-                               .call =  GIC_IPI_EXT_INTR_CALLFNC_VPE1
-                       }, {
-                               .resched = GIC_IPI_EXT_INTR_RESCHED_VPE2,
-                               .call =  GIC_IPI_EXT_INTR_CALLFNC_VPE2
-                       }, {
-                               .resched = GIC_IPI_EXT_INTR_RESCHED_VPE3,
-                               .call =  GIC_IPI_EXT_INTR_CALLFNC_VPE3
-                       }
-               };
+
+               gic_call_int_base = GIC_NUM_INTRS - NR_CPUS;
+               gic_resched_int_base = gic_call_int_base - NR_CPUS;
+
                fill_ipi_map();
                gic_init(GIC_BASE_ADDR, GIC_ADDRSPACE_SZ, gic_intr_map, ARRAY_SIZE(gic_intr_map), MIPS_GIC_IRQ_BASE);
                if (!gcmp_present) {
@@ -553,12 +555,15 @@ void __init arch_init_irq(void)
                printk("CPU%d: status register now %08x\n", smp_processor_id(), read_c0_status());
                write_c0_status(0x1100dc00);
                printk("CPU%d: status register frc %08x\n", smp_processor_id(), read_c0_status());
-               for (i = 0; i < ARRAY_SIZE(ipiirq); i++) {
-                       setup_irq(MIPS_GIC_IRQ_BASE + ipiirq[i].resched, &irq_resched);
-                       setup_irq(MIPS_GIC_IRQ_BASE + ipiirq[i].call, &irq_call);
-
-                       set_irq_handler(MIPS_GIC_IRQ_BASE + ipiirq[i].resched, handle_percpu_irq);
-                       set_irq_handler(MIPS_GIC_IRQ_BASE + ipiirq[i].call, handle_percpu_irq);
+               for (i = 0; i < NR_CPUS; i++) {
+                       setup_irq(MIPS_GIC_IRQ_BASE +
+                                       GIC_RESCHED_INT(i), &irq_resched);
+                       setup_irq(MIPS_GIC_IRQ_BASE +
+                                       GIC_CALL_INT(i), &irq_call);
+                       set_irq_handler(MIPS_GIC_IRQ_BASE +
+                                       GIC_RESCHED_INT(i), handle_percpu_irq);
+                       set_irq_handler(MIPS_GIC_IRQ_BASE +
+                                       GIC_CALL_INT(i), handle_percpu_irq);
                }
        } else {
                /* set up ipi interrupts */
index 42dee4d..f48d60e 100644 (file)
@@ -28,9 +28,6 @@
 #include <asm/reboot.h>
 #include <asm/mips-boards/generic.h>
 
-static void mips_machine_restart(char *command);
-static void mips_machine_halt(void);
-
 static void mips_machine_restart(char *command)
 {
        unsigned int __iomem *softres_reg =
index e8a97f5..63d8a29 100644 (file)
@@ -52,3 +52,8 @@ obj-$(CONFIG_VICTOR_MPC30X)   += fixup-mpc30x.o
 obj-$(CONFIG_ZAO_CAPCELLA)     += fixup-capcella.o
 obj-$(CONFIG_WR_PPMC)          += fixup-wrppmc.o
 obj-$(CONFIG_MIKROTIK_RB532)   += pci-rc32434.o ops-rc32434.o fixup-rc32434.o
+obj-$(CONFIG_CPU_CAVIUM_OCTEON)        += pci-octeon.o pcie-octeon.o
+
+ifdef CONFIG_PCI_MSI
+obj-$(CONFIG_CPU_CAVIUM_OCTEON)        += msi-octeon.o
+endif
index 1416bca..1c02f57 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  fixup-cappcela.c, The ZAO Networks Capcella specific PCI fixups.
  *
- *  Copyright (C) 2002,2004  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *  Copyright (C) 2002,2004  Yoichi Yuasa <yuasa@linux-mips.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
index 5911596..e08f49c 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  fixup-mpc30x.c, The Victor MP-C303/304 specific PCI fixups.
  *
- *  Copyright (C) 2002,2004  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *  Copyright (C) 2002,2004  Yoichi Yuasa <yuasa@linux-mips.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
index ed87733..8084b17 100644 (file)
@@ -2,7 +2,7 @@
  *  fixup-tb0219.c, The TANBAC TB0219 specific PCI fixups.
  *
  *  Copyright (C) 2003  Megasolution Inc. <matsu@megasolution.jp>
- *  Copyright (C) 2004-2005  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *  Copyright (C) 2004-2005  Yoichi Yuasa <yuasa@linux-mips.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
index e3eedf4..4196ccf 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  fixup-tb0226.c, The TANBAC TB0226 specific PCI fixups.
  *
- *  Copyright (C) 2002-2005  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *  Copyright (C) 2002-2005  Yoichi Yuasa <yuasa@linux-mips.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
index 267ab3d..2fe29db 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  fixup-tb0287.c, The TANBAC TB0287 specific PCI fixups.
  *
- *  Copyright (C) 2005  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *  Copyright (C) 2005  Yoichi Yuasa <yuasa@linux-mips.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
similarity index 88%
rename from arch/mips/cavium-octeon/msi.c
rename to arch/mips/pci/msi-octeon.c
index 964b03b..03742e6 100644 (file)
@@ -3,7 +3,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 2005-2007 Cavium Networks
+ * Copyright (C) 2005-2009 Cavium Networks
  */
 #include <linux/kernel.h>
 #include <linux/init.h>
@@ -16,8 +16,7 @@
 #include <asm/octeon/cvmx-pci-defs.h>
 #include <asm/octeon/cvmx-npei-defs.h>
 #include <asm/octeon/cvmx-pexp-defs.h>
-
-#include "pci-common.h"
+#include <asm/octeon/pci-octeon.h>
 
 /*
  * Each bit in msi_free_irq_bitmask represents a MSI interrupt that is
@@ -47,8 +46,8 @@ static DEFINE_SPINLOCK(msi_free_irq_bitmask_lock);
  * programming the MSI control bits [6:4] before calling
  * pci_enable_msi().
  *
- * @param dev    Device requesting MSI interrupts
- * @param desc   MSI descriptor
+ * @dev:    Device requesting MSI interrupts
+ * @desc:   MSI descriptor
  *
  * Returns 0 on success.
  */
@@ -213,14 +212,9 @@ void arch_teardown_msi_irq(unsigned int irq)
 }
 
 
-/**
+/*
  * Called by the interrupt handling code when an MSI interrupt
  * occurs.
- *
- * @param cpl
- * @param dev_id
- *
- * @return
  */
 static irqreturn_t octeon_msi_interrupt(int cpl, void *dev_id)
 {
@@ -256,31 +250,37 @@ static irqreturn_t octeon_msi_interrupt(int cpl, void *dev_id)
 }
 
 
-/**
+/*
  * Initializes the MSI interrupt handling code
- *
- * @return
  */
 int octeon_msi_initialize(void)
 {
-       int r;
        if (octeon_has_feature(OCTEON_FEATURE_PCIE)) {
-               r = request_irq(OCTEON_IRQ_PCI_MSI0, octeon_msi_interrupt,
+               if (request_irq(OCTEON_IRQ_PCI_MSI0, octeon_msi_interrupt,
                                IRQF_SHARED,
-                               "MSI[0:63]", octeon_msi_interrupt);
+                               "MSI[0:63]", octeon_msi_interrupt))
+                       panic("request_irq(OCTEON_IRQ_PCI_MSI0) failed");
        } else if (octeon_is_pci_host()) {
-               r = request_irq(OCTEON_IRQ_PCI_MSI0, octeon_msi_interrupt,
+               if (request_irq(OCTEON_IRQ_PCI_MSI0, octeon_msi_interrupt,
                                IRQF_SHARED,
-                               "MSI[0:15]", octeon_msi_interrupt);
-               r += request_irq(OCTEON_IRQ_PCI_MSI1, octeon_msi_interrupt,
-                                IRQF_SHARED,
-                                "MSI[16:31]", octeon_msi_interrupt);
-               r += request_irq(OCTEON_IRQ_PCI_MSI2, octeon_msi_interrupt,
-                                IRQF_SHARED,
-                                "MSI[32:47]", octeon_msi_interrupt);
-               r += request_irq(OCTEON_IRQ_PCI_MSI3, octeon_msi_interrupt,
-                                IRQF_SHARED,
-                                "MSI[48:63]", octeon_msi_interrupt);
+                               "MSI[0:15]", octeon_msi_interrupt))
+                       panic("request_irq(OCTEON_IRQ_PCI_MSI0) failed");
+
+               if (request_irq(OCTEON_IRQ_PCI_MSI1, octeon_msi_interrupt,
+                               IRQF_SHARED,
+                               "MSI[16:31]", octeon_msi_interrupt))
+                       panic("request_irq(OCTEON_IRQ_PCI_MSI1) failed");
+
+               if (request_irq(OCTEON_IRQ_PCI_MSI2, octeon_msi_interrupt,
+                               IRQF_SHARED,
+                               "MSI[32:47]", octeon_msi_interrupt))
+                       panic("request_irq(OCTEON_IRQ_PCI_MSI2) failed");
+
+               if (request_irq(OCTEON_IRQ_PCI_MSI3, octeon_msi_interrupt,
+                               IRQF_SHARED,
+                               "MSI[48:63]", octeon_msi_interrupt))
+                       panic("request_irq(OCTEON_IRQ_PCI_MSI3) failed");
+
        }
        return 0;
 }
index 900c6b3..28962a7 100644 (file)
@@ -2,8 +2,8 @@
  *  ops-vr41xx.c, PCI configuration routines for the PCIU of NEC VR4100 series.
  *
  *  Copyright (C) 2001-2003 MontaVista Software Inc.
- *    Author: Yoichi Yuasa <yyuasa@mvista.com or source@mvista.com>
- *  Copyright (C) 2004-2005  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *    Author: Yoichi Yuasa <source@mvista.com>
+ *  Copyright (C) 2004-2005  Yoichi Yuasa <yuasa@linux-mips.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
@@ -21,7 +21,7 @@
  */
 /*
  * Changes:
- *  MontaVista Software Inc. <yyuasa@mvista.com> or <source@mvista.com>
+ *  MontaVista Software Inc. <source@mvista.com>
  *  - New creation, NEC VR4122 and VR4131 are supported.
  */
 #include <linux/pci.h>
similarity index 78%
rename from arch/mips/cavium-octeon/pci.c
rename to arch/mips/pci/pci-octeon.c
index 67c0ff5..9cb0c80 100644 (file)
@@ -3,7 +3,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 2005-2007 Cavium Networks
+ * Copyright (C) 2005-2009 Cavium Networks
  */
 #include <linux/kernel.h>
 #include <linux/init.h>
@@ -17,8 +17,7 @@
 #include <asm/octeon/octeon.h>
 #include <asm/octeon/cvmx-npi-defs.h>
 #include <asm/octeon/cvmx-pci-defs.h>
-
-#include "pci-common.h"
+#include <asm/octeon/pci-octeon.h>
 
 #define USE_OCTEON_INTERNAL_ARBITER
 
@@ -54,6 +53,126 @@ union octeon_pci_address {
        } s;
 };
 
+int __initdata (*octeon_pcibios_map_irq)(const struct pci_dev *dev,
+                                        u8 slot, u8 pin);
+enum octeon_dma_bar_type octeon_dma_bar_type = OCTEON_DMA_BAR_TYPE_INVALID;
+
+/**
+ * Map a PCI device to the appropriate interrupt line
+ *
+ * @dev:    The Linux PCI device structure for the device to map
+ * @slot:   The slot number for this device on __BUS 0__. Linux
+ *               enumerates through all the bridges and figures out the
+ *               slot on Bus 0 where this device eventually hooks to.
+ * @pin:    The PCI interrupt pin read from the device, then swizzled
+ *               as it goes through each bridge.
+ * Returns Interrupt number for the device
+ */
+int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
+{
+       if (octeon_pcibios_map_irq)
+               return octeon_pcibios_map_irq(dev, slot, pin);
+       else
+               panic("octeon_pcibios_map_irq not set.");
+}
+
+
+/*
+ * Called to perform platform specific PCI setup
+ */
+int pcibios_plat_dev_init(struct pci_dev *dev)
+{
+       uint16_t config;
+       uint32_t dconfig;
+       int pos;
+       /*
+        * Force the Cache line setting to 64 bytes. The standard
+        * Linux bus scan doesn't seem to set it. Octeon really has
+        * 128 byte lines, but Intel bridges get really upset if you
+        * try and set values above 64 bytes. Value is specified in
+        * 32bit words.
+        */
+       pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 64 / 4);
+       /* Set latency timers for all devices */
+       pci_write_config_byte(dev, PCI_LATENCY_TIMER, 48);
+
+       /* Enable reporting System errors and parity errors on all devices */
+       /* Enable parity checking and error reporting */
+       pci_read_config_word(dev, PCI_COMMAND, &config);
+       config |= PCI_COMMAND_PARITY | PCI_COMMAND_SERR;
+       pci_write_config_word(dev, PCI_COMMAND, config);
+
+       if (dev->subordinate) {
+               /* Set latency timers on sub bridges */
+               pci_write_config_byte(dev, PCI_SEC_LATENCY_TIMER, 48);
+               /* More bridge error detection */
+               pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &config);
+               config |= PCI_BRIDGE_CTL_PARITY | PCI_BRIDGE_CTL_SERR;
+               pci_write_config_word(dev, PCI_BRIDGE_CONTROL, config);
+       }
+
+       /* Enable the PCIe normal error reporting */
+       pos = pci_find_capability(dev, PCI_CAP_ID_EXP);
+       if (pos) {
+               /* Update Device Control */
+               pci_read_config_word(dev, pos + PCI_EXP_DEVCTL, &config);
+               /* Correctable Error Reporting */
+               config |= PCI_EXP_DEVCTL_CERE;
+               /* Non-Fatal Error Reporting */
+               config |= PCI_EXP_DEVCTL_NFERE;
+               /* Fatal Error Reporting */
+               config |= PCI_EXP_DEVCTL_FERE;
+               /* Unsupported Request */
+               config |= PCI_EXP_DEVCTL_URRE;
+               pci_write_config_word(dev, pos + PCI_EXP_DEVCTL, config);
+       }
+
+       /* Find the Advanced Error Reporting capability */
+       pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
+       if (pos) {
+               /* Clear Uncorrectable Error Status */
+               pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS,
+                                     &dconfig);
+               pci_write_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS,
+                                      dconfig);
+               /* Enable reporting of all uncorrectable errors */
+               /* Uncorrectable Error Mask - turned on bits disable errors */
+               pci_write_config_dword(dev, pos + PCI_ERR_UNCOR_MASK, 0);
+               /*
+                * Leave severity at HW default. This only controls if
+                * errors are reported as uncorrectable or
+                * correctable, not if the error is reported.
+                */
+               /* PCI_ERR_UNCOR_SEVER - Uncorrectable Error Severity */
+               /* Clear Correctable Error Status */
+               pci_read_config_dword(dev, pos + PCI_ERR_COR_STATUS, &dconfig);
+               pci_write_config_dword(dev, pos + PCI_ERR_COR_STATUS, dconfig);
+               /* Enable reporting of all correctable errors */
+               /* Correctable Error Mask - turned on bits disable errors */
+               pci_write_config_dword(dev, pos + PCI_ERR_COR_MASK, 0);
+               /* Advanced Error Capabilities */
+               pci_read_config_dword(dev, pos + PCI_ERR_CAP, &dconfig);
+               /* ECRC Generation Enable */
+               if (config & PCI_ERR_CAP_ECRC_GENC)
+                       config |= PCI_ERR_CAP_ECRC_GENE;
+               /* ECRC Check Enable */
+               if (config & PCI_ERR_CAP_ECRC_CHKC)
+                       config |= PCI_ERR_CAP_ECRC_CHKE;
+               pci_write_config_dword(dev, pos + PCI_ERR_CAP, dconfig);
+               /* PCI_ERR_HEADER_LOG - Header Log Register (16 bytes) */
+               /* Report all errors to the root complex */
+               pci_write_config_dword(dev, pos + PCI_ERR_ROOT_COMMAND,
+                                      PCI_ERR_ROOT_CMD_COR_EN |
+                                      PCI_ERR_ROOT_CMD_NONFATAL_EN |
+                                      PCI_ERR_ROOT_CMD_FATAL_EN);
+               /* Clear the Root status register */
+               pci_read_config_dword(dev, pos + PCI_ERR_ROOT_STATUS, &dconfig);
+               pci_write_config_dword(dev, pos + PCI_ERR_ROOT_STATUS, dconfig);
+       }
+
+       return 0;
+}
+
 /**
  * Return the mapping of PCI device number to IRQ line. Each
  * character in the return string represents the interrupt
@@ -136,9 +255,8 @@ int __init octeon_pci_pcibios_map_irq(const struct pci_dev *dev,
 }
 
 
-/**
+/*
  * Read a value from configuration space
- *
  */
 static int octeon_read_config(struct pci_bus *bus, unsigned int devfn,
                              int reg, int size, u32 *val)
@@ -174,15 +292,8 @@ static int octeon_read_config(struct pci_bus *bus, unsigned int devfn,
 }
 
 
-/**
+/*
  * Write a value to PCI configuration space
- *
- * @bus:
- * @devfn:
- * @reg:
- * @size:
- * @val:
- * Returns
  */
 static int octeon_write_config(struct pci_bus *bus, unsigned int devfn,
                               int reg, int size, u32 val)
@@ -251,10 +362,8 @@ static struct pci_controller octeon_pci_controller = {
 };
 
 
-/**
+/*
  * Low level initialize the Octeon PCI controller
- *
- * Returns
  */
 static void octeon_pci_initialize(void)
 {
@@ -398,7 +507,7 @@ static void octeon_pci_initialize(void)
                pci_int_arb_cfg.s.en = 1;       /* Internal arbiter enable */
                cvmx_write_csr(CVMX_NPI_PCI_INT_ARB_CFG, pci_int_arb_cfg.u64);
        }
-#endif                         /* USE_OCTEON_INTERNAL_ARBITER */
+#endif /* USE_OCTEON_INTERNAL_ARBITER */
 
        /*
         * Preferrably written to 1 to set MLTD. [RDSATI,TRTAE,
@@ -457,10 +566,8 @@ static void octeon_pci_initialize(void)
 }
 
 
-/**
+/*
  * Initialize the Octeon PCI controller
- *
- * Returns
  */
 static int __init octeon_pci_setup(void)
 {
index d1e049b..5652571 100644 (file)
@@ -2,8 +2,8 @@
  *  pci-vr41xx.c, PCI Control Unit routines for the NEC VR4100 series.
  *
  *  Copyright (C) 2001-2003 MontaVista Software Inc.
- *    Author: Yoichi Yuasa <yyuasa@mvista.com or source@mvista.com>
- *  Copyright (C) 2004-2008  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *    Author: Yoichi Yuasa <source@mvista.com>
+ *  Copyright (C) 2004-2008  Yoichi Yuasa <yuasa@linux-mips.org>
  *  Copyright (C) 2004 by Ralf Baechle (ralf@linux-mips.org)
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -22,7 +22,7 @@
  */
 /*
  * Changes:
- *  MontaVista Software Inc. <yyuasa@mvista.com> or <source@mvista.com>
+ *  MontaVista Software Inc. <source@mvista.com>
  *  - New creation, NEC VR4122 and VR4131 are supported.
  */
 #include <linux/init.h>
index 8a35e32..6b1ae2e 100644 (file)
@@ -2,8 +2,8 @@
  *  pci-vr41xx.h, Include file for PCI Control Unit of the NEC VR4100 series.
  *
  *  Copyright (C) 2002  MontaVista Software Inc.
- *    Author: Yoichi Yuasa <yyuasa@mvista.com or source@mvista.com>
- *  Copyright (C) 2004-2005  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *    Author: Yoichi Yuasa <source@mvista.com>
+ *  Copyright (C) 2004-2005  Yoichi Yuasa <yuasa@linux-mips.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
similarity index 98%
rename from arch/mips/cavium-octeon/pcie.c
rename to arch/mips/pci/pcie-octeon.c
index 49d1408..7526224 100644 (file)
@@ -18,8 +18,7 @@
 #include <asm/octeon/cvmx-pescx-defs.h>
 #include <asm/octeon/cvmx-pexp-defs.h>
 #include <asm/octeon/cvmx-helper-errata.h>
-
-#include "pci-common.h"
+#include <asm/octeon/pci-octeon.h>
 
 union cvmx_pcie_address {
        uint64_t u64;
@@ -976,13 +975,13 @@ static int cvmx_pcie_rc_initialize(int pcie_port)
 /**
  * Map a PCI device to the appropriate interrupt line
  *
- * @param dev    The Linux PCI device structure for the device to map
- * @param slot   The slot number for this device on __BUS 0__. Linux
+ * @dev:    The Linux PCI device structure for the device to map
+ * @slot:   The slot number for this device on __BUS 0__. Linux
  *               enumerates through all the bridges and figures out the
  *               slot on Bus 0 where this device eventually hooks to.
- * @param pin    The PCI interrupt pin read from the device, then swizzled
+ * @pin:    The PCI interrupt pin read from the device, then swizzled
  *               as it goes through each bridge.
- * @return Interrupt number for the device
+ * Returns Interrupt number for the device
  */
 int __init octeon_pcie_pcibios_map_irq(const struct pci_dev *dev,
                                       u8 slot, u8 pin)
@@ -1025,12 +1024,12 @@ int __init octeon_pcie_pcibios_map_irq(const struct pci_dev *dev,
 /**
  * Read a value from configuration space
  *
- * @param bus
- * @param devfn
- * @param reg
- * @param size
- * @param val
- * @return
+ * @bus:
+ * @devfn:
+ * @reg:
+ * @size:
+ * @val:
+ * Returns
  */
 static inline int octeon_pcie_read_config(int pcie_port, struct pci_bus *bus,
                                          unsigned int devfn, int reg, int size,
@@ -1156,12 +1155,12 @@ static int octeon_pcie1_read_config(struct pci_bus *bus, unsigned int devfn,
 /**
  * Write a value to PCI configuration space
  *
- * @param bus
- * @param devfn
- * @param reg
- * @param size
- * @param val
- * @return
+ * @bus:
+ * @devfn:
+ * @reg:
+ * @size:
+ * @val:
+ * Returns
  */
 static inline int octeon_pcie_write_config(int pcie_port, struct pci_bus *bus,
                                           unsigned int devfn, int reg,
@@ -1254,7 +1253,7 @@ static struct pci_controller octeon_pcie1_controller = {
 /**
  * Initialize the Octeon PCIe controllers
  *
- * @return
+ * Returns
  */
 static int __init octeon_pcie_setup(void)
 {
index 6d9bab8..719f4a5 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  setup.c, Setup for the CASIO CASSIOPEIA E-11/15/55/65.
  *
- *  Copyright (C) 2002-2006  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *  Copyright (C) 2002-2006  Yoichi Yuasa <yuasa@linux-mips.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
index d77c330..6346c59 100644 (file)
@@ -2,8 +2,8 @@
  *  bcu.c, Bus Control Unit routines for the NEC VR4100 series.
  *
  *  Copyright (C) 2002  MontaVista Software Inc.
- *    Author: Yoichi Yuasa <yyuasa@mvista.com, or source@mvista.com>
- *  Copyright (C) 2003-2005  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *    Author: Yoichi Yuasa <source@mvista.com>
+ *  Copyright (C) 2003-2005  Yoichi Yuasa <yuasa@linux-mips.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
  */
 /*
  * Changes:
- *  MontaVista Software Inc. <yyuasa@mvista.com> or <source@mvista.com>
+ *  MontaVista Software Inc. <source@mvista.com>
  *  - New creation, NEC VR4122 and VR4131 are supported.
  *  - Added support for NEC VR4111 and VR4121.
  *
- *  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *  Yoichi Yuasa <yuasa@linux-mips.org>
  *  - Added support for NEC VR4133.
  */
 #include <linux/kernel.h>
index ad0e8e3..8ba7d04 100644 (file)
@@ -2,8 +2,8 @@
  *  cmu.c, Clock Mask Unit routines for the NEC VR4100 series.
  *
  *  Copyright (C) 2001-2002  MontaVista Software Inc.
- *    Author: Yoichi Yuasa <yyuasa@mvista.com or source@mvista.com>
- *  Copuright (C) 2003-2005  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *    Author: Yoichi Yuasa <source@mvista.com>
+ *  Copuright (C) 2003-2005  Yoichi Yuasa <yuasa@linux-mips.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
  */
 /*
  * Changes:
- *  MontaVista Software Inc. <yyuasa@mvista.com> or <source@mvista.com>
+ *  MontaVista Software Inc. <source@mvista.com>
  *  - New creation, NEC VR4122 and VR4131 are supported.
  *  - Added support for NEC VR4111 and VR4121.
  *
- *  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *  Yoichi Yuasa <yuasa@linux-mips.org>
  *  - Added support for NEC VR4133.
  */
 #include <linux/init.h>
index 2b272f1..22cc6f2 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  NEC VR4100 series GIU platform device.
  *
- *  Copyright (C) 2007  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *  Copyright (C) 2007  Yoichi Yuasa <yuasa@linux-mips.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
index 3f23d9f..6d39e22 100644 (file)
@@ -2,8 +2,8 @@
  *  icu.c, Interrupt Control Unit routines for the NEC VR4100 series.
  *
  *  Copyright (C) 2001-2002  MontaVista Software Inc.
- *    Author: Yoichi Yuasa <yyuasa@mvista.com or source@mvista.com>
- *  Copyright (C) 2003-2006  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *    Author: Yoichi Yuasa <source@mvista.com>
+ *  Copyright (C) 2003-2006  Yoichi Yuasa <yuasa@linux-mips.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
  */
 /*
  * Changes:
- *  MontaVista Software Inc. <yyuasa@mvista.com> or <source@mvista.com>
+ *  MontaVista Software Inc. <source@mvista.com>
  *  - New creation, NEC VR4122 and VR4131 are supported.
  *  - Added support for NEC VR4111 and VR4121.
  *
- *  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *  Yoichi Yuasa <yuasa@linux-mips.org>
  *  - Coped with INTASSIGN of NEC VR4133.
  */
 #include <linux/errno.h>
index c649953..1386e6f 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  init.c, Common initialization routines for NEC VR4100 series.
  *
- *  Copyright (C) 2003-2008  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *  Copyright (C) 2003-2008  Yoichi Yuasa <yuasa@linux-mips.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
index 9cc3891..bef0687 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  Interrupt handing routines for NEC VR4100 series.
  *
- *  Copyright (C) 2005-2007  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *  Copyright (C) 2005-2007  Yoichi Yuasa <yuasa@linux-mips.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
index 028aaf7..692b4e8 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  pmu.c, Power Management Unit routines for NEC VR4100 series.
  *
- *  Copyright (C) 2003-2007  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *  Copyright (C) 2003-2007  Yoichi Yuasa <yuasa@linux-mips.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
index 9f26c14..ebc5dcf 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  NEC VR4100 series RTC platform device.
  *
- *  Copyright (C) 2007  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *  Copyright (C) 2007  Yoichi Yuasa <yuasa@linux-mips.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
index 654dee6..54eae56 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  NEC VR4100 series SIU platform device.
  *
- *  Copyright (C) 2007-2008  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *  Copyright (C) 2007-2008  Yoichi Yuasa <yuasa@linux-mips.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
index e0c1ac5..ff84142 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  type.c, System type for NEC VR4100 series.
  *
- *  Copyright (C) 2005  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *  Copyright (C) 2005  Yoichi Yuasa <yuasa@linux-mips.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
index 9eef297..3982f37 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  setup.c, Setup for the IBM WorkPad z50.
  *
- *  Copyright (C) 2002-2006  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *  Copyright (C) 2002-2006  Yoichi Yuasa <yuasa@linux-mips.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
index fef5b43..fad6861 100644 (file)
 #define __NR_inotify_init1     333
 #define __NR_preadv            334
 #define __NR_pwritev           335
+#define __NR_rt_tgsigqueueinfo 336
+#define __NR_perf_counter_open 337
 
 #ifdef __KERNEL__
 
-#define NR_syscalls 326
+#define NR_syscalls 338
 
 /*
  * specify the deprecated syscalls we want to support on this arch
index 7408a27..e0d2563 100644 (file)
@@ -722,6 +722,8 @@ ENTRY(sys_call_table)
        .long sys_inotify_init1
        .long sys_preadv
        .long sys_pwritev               /* 335 */
+       .long sys_rt_tgsigqueueinfo
+       .long sys_perf_counter_open
 
 
 nr_syscalls=(.-sys_call_table)/4
index bcebcef..c96ba3d 100644 (file)
@@ -61,7 +61,7 @@ SECTIONS
        _edata = .;             /* End of data section */
   }
 
-  .data.init_task : { INIT_TASK(THREAD_SIZE); }
+  .data.init_task : { INIT_TASK_DATA(THREAD_SIZE); }
 
   /* might get freed after init */
   . = ALIGN(PAGE_SIZE);
index 9038f39..06f8d5b 100644 (file)
@@ -16,6 +16,8 @@ config PARISC
        select RTC_DRV_GENERIC
        select INIT_ALL_POSSIBLE
        select BUG
+       select HAVE_PERF_COUNTERS
+       select GENERIC_ATOMIC64 if !64BIT
        help
          The PA-RISC microprocessor is designed by Hewlett-Packard and used
          in many of their workstations & servers (HP9000 700 and 800 series,
index 7eeaff9..8bc9e96 100644 (file)
@@ -222,13 +222,13 @@ static __inline__ int atomic_add_unless(atomic_t *v, int a, int u)
 
 #define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
 
-#define atomic_add(i,v)        ((void)(__atomic_add_return( ((int)(i)),(v))))
-#define atomic_sub(i,v)        ((void)(__atomic_add_return(-((int)(i)),(v))))
+#define atomic_add(i,v)        ((void)(__atomic_add_return( (i),(v))))
+#define atomic_sub(i,v)        ((void)(__atomic_add_return(-(i),(v))))
 #define atomic_inc(v)  ((void)(__atomic_add_return(   1,(v))))
 #define atomic_dec(v)  ((void)(__atomic_add_return(  -1,(v))))
 
-#define atomic_add_return(i,v) (__atomic_add_return( ((int)(i)),(v)))
-#define atomic_sub_return(i,v) (__atomic_add_return(-((int)(i)),(v)))
+#define atomic_add_return(i,v) (__atomic_add_return( (i),(v)))
+#define atomic_sub_return(i,v) (__atomic_add_return(-(i),(v)))
 #define atomic_inc_return(v)   (__atomic_add_return(   1,(v)))
 #define atomic_dec_return(v)   (__atomic_add_return(  -1,(v)))
 
@@ -336,7 +336,11 @@ static __inline__ int atomic64_add_unless(atomic64_t *v, long a, long u)
 
 #define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0)
 
-#endif /* CONFIG_64BIT */
+#else /* CONFIG_64BIT */
+
+#include <asm-generic/atomic64.h>
+
+#endif /* !CONFIG_64BIT */
 
 #include <asm-generic/atomic-long.h>
 
index 31ad0f0..f7a18f9 100644 (file)
@@ -1,5 +1,4 @@
-/* $Id: dma.h,v 1.2 1999/04/27 00:46:18 deller Exp $
- * linux/include/asm/dma.h: Defines for using and allocating dma channels.
+/* asm/dma.h: Defines for using and allocating dma channels.
  * Written by Hennus Bergman, 1992.
  * High DMA channel support & info by Hannu Savolainen
  * and John Boyd, Nov. 1992.
diff --git a/arch/parisc/include/asm/perf_counter.h b/arch/parisc/include/asm/perf_counter.h
new file mode 100644 (file)
index 0000000..dc9e829
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef __ASM_PARISC_PERF_COUNTER_H
+#define __ASM_PARISC_PERF_COUNTER_H
+
+/* parisc only supports software counters through this interface. */
+static inline void set_perf_counter_pending(void) { }
+
+#endif /* __ASM_PARISC_PERF_COUNTER_H */
index 9d64df8..9ce66e9 100644 (file)
@@ -18,6 +18,7 @@
 #include <asm/types.h>
 #include <asm/system.h>
 #include <asm/percpu.h>
+
 #endif /* __ASSEMBLY__ */
 
 #define KERNEL_STACK_SIZE      (4*PAGE_SIZE)
@@ -127,6 +128,8 @@ struct thread_struct {
        unsigned long  flags;
 }; 
 
+#define task_pt_regs(tsk) ((struct pt_regs *)&((tsk)->thread.regs))
+
 /* Thread struct flags. */
 #define PARISC_UAC_NOPRINT     (1UL << 0)      /* see prctl and unaligned.c */
 #define PARISC_UAC_SIGBUS      (1UL << 1)
index ee80c92..d91357b 100644 (file)
@@ -168,8 +168,8 @@ static inline void set_eiem(unsigned long val)
 /* LDCW, the only atomic read-write operation PA-RISC has. *sigh*.  */
 #define __ldcw(a) ({                                           \
        unsigned __ret;                                         \
-       __asm__ __volatile__(__LDCW " 0(%1),%0"                 \
-               : "=r" (__ret) : "r" (a));                      \
+       __asm__ __volatile__(__LDCW " 0(%2),%0"                 \
+               : "=r" (__ret), "+m" (*(a)) : "r" (a));         \
        __ret;                                                  \
 })
 
index 1f6fd4f..8f1a810 100644 (file)
  * N class systems, only one PxTLB inter processor broadcast can be
  * active at any one time on the Merced bus.  This tlb purge
  * synchronisation is fairly lightweight and harmless so we activate
- * it on all SMP systems not just the N class.  We also need to have
- * preemption disabled on uniprocessor machines, and spin_lock does that
- * nicely.
+ * it on all systems not just the N class.
  */
 extern spinlock_t pa_tlb_lock;
 
-#define purge_tlb_start(x) spin_lock(&pa_tlb_lock)
-#define purge_tlb_end(x) spin_unlock(&pa_tlb_lock)
+#define purge_tlb_start(flags) spin_lock_irqsave(&pa_tlb_lock, flags)
+#define purge_tlb_end(flags)   spin_unlock_irqrestore(&pa_tlb_lock, flags)
 
 extern void flush_tlb_all(void);
 extern void flush_tlb_all_local(void *);
@@ -63,14 +61,16 @@ static inline void flush_tlb_mm(struct mm_struct *mm)
 static inline void flush_tlb_page(struct vm_area_struct *vma,
        unsigned long addr)
 {
+       unsigned long flags;
+
        /* For one page, it's not worth testing the split_tlb variable */
 
        mb();
        mtsp(vma->vm_mm->context,1);
-       purge_tlb_start();
+       purge_tlb_start(flags);
        pdtlb(addr);
        pitlb(addr);
-       purge_tlb_end();
+       purge_tlb_end(flags);
 }
 
 void __flush_tlb_range(unsigned long sid,
index ef26b00..f3d3b8b 100644 (file)
 #define __NR_dup3              (__NR_Linux + 312)
 #define __NR_pipe2             (__NR_Linux + 313)
 #define __NR_inotify_init1     (__NR_Linux + 314)
+#define __NR_preadv            (__NR_Linux + 315)
+#define __NR_pwritev           (__NR_Linux + 316)
+#define __NR_rt_tgsigqueueinfo (__NR_Linux + 317)
+#define __NR_perf_counter_open (__NR_Linux + 318)
 
-#define __NR_Linux_syscalls    (__NR_inotify_init1 + 1)
+#define __NR_Linux_syscalls    (__NR_perf_counter_open + 1)
 
 
 #define __IGNORE_select                /* newselect */
index 837530e..b6ed34d 100644 (file)
@@ -1,5 +1,4 @@
-/* $Id: cache.c,v 1.4 2000/01/25 00:11:38 prumpf Exp $
- *
+/*
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
@@ -398,12 +397,13 @@ EXPORT_SYMBOL(flush_kernel_icache_range_asm);
 
 void clear_user_page_asm(void *page, unsigned long vaddr)
 {
+       unsigned long flags;
        /* This function is implemented in assembly in pacache.S */
        extern void __clear_user_page_asm(void *page, unsigned long vaddr);
 
-       purge_tlb_start();
+       purge_tlb_start(flags);
        __clear_user_page_asm(page, vaddr);
-       purge_tlb_end();
+       purge_tlb_end(flags);
 }
 
 #define FLUSH_THRESHOLD 0x80000 /* 0.5MB */
@@ -444,20 +444,24 @@ extern void clear_user_page_asm(void *page, unsigned long vaddr);
 
 void clear_user_page(void *page, unsigned long vaddr, struct page *pg)
 {
+       unsigned long flags;
+
        purge_kernel_dcache_page((unsigned long)page);
-       purge_tlb_start();
+       purge_tlb_start(flags);
        pdtlb_kernel(page);
-       purge_tlb_end();
+       purge_tlb_end(flags);
        clear_user_page_asm(page, vaddr);
 }
 EXPORT_SYMBOL(clear_user_page);
 
 void flush_kernel_dcache_page_addr(void *addr)
 {
+       unsigned long flags;
+
        flush_kernel_dcache_page_asm(addr);
-       purge_tlb_start();
+       purge_tlb_start(flags);
        pdtlb_kernel(addr);
-       purge_tlb_end();
+       purge_tlb_end(flags);
 }
 EXPORT_SYMBOL(flush_kernel_dcache_page_addr);
 
@@ -490,8 +494,10 @@ void __flush_tlb_range(unsigned long sid, unsigned long start,
        if (npages >= 512)  /* 2MB of space: arbitrary, should be tuned */
                flush_tlb_all();
        else {
+               unsigned long flags;
+
                mtsp(sid, 1);
-               purge_tlb_start();
+               purge_tlb_start(flags);
                if (split_tlb) {
                        while (npages--) {
                                pdtlb(start);
@@ -504,7 +510,7 @@ void __flush_tlb_range(unsigned long sid, unsigned long start,
                                start += PAGE_SIZE;
                        }
                }
-               purge_tlb_end();
+               purge_tlb_end(flags);
        }
 }
 
index bd1f7f1..d228d82 100644 (file)
@@ -170,23 +170,27 @@ static void __init pagezero_memconfig(void)
 static int __init 
 pat_query_module(ulong pcell_loc, ulong mod_index)
 {
-       pdc_pat_cell_mod_maddr_block_t pa_pdc_cell;
+       pdc_pat_cell_mod_maddr_block_t *pa_pdc_cell;
        unsigned long bytecnt;
        unsigned long temp;     /* 64-bit scratch value */
        long status;            /* PDC return value status */
        struct parisc_device *dev;
 
+       pa_pdc_cell = kmalloc(sizeof (*pa_pdc_cell), GFP_KERNEL);
+       if (!pa_pdc_cell)
+               panic("couldn't allocate memory for PDC_PAT_CELL!");
+
        /* return cell module (PA or Processor view) */
        status = pdc_pat_cell_module(&bytecnt, pcell_loc, mod_index,
-                                    PA_VIEW, &pa_pdc_cell);
+                                    PA_VIEW, pa_pdc_cell);
 
        if (status != PDC_OK) {
                /* no more cell modules or error */
                return status;
        }
 
-       temp = pa_pdc_cell.cba;
-       dev = alloc_pa_dev(PAT_GET_CBA(temp), &pa_pdc_cell.mod_path);
+       temp = pa_pdc_cell->cba;
+       dev = alloc_pa_dev(PAT_GET_CBA(temp), &(pa_pdc_cell->mod_path));
        if (!dev) {
                return PDC_OK;
        }
@@ -203,8 +207,8 @@ pat_query_module(ulong pcell_loc, ulong mod_index)
 
        /* save generic info returned from the call */
        /* REVISIT: who is the consumer of this? not sure yet... */
-       dev->mod_info = pa_pdc_cell.mod_info;   /* pass to PAT_GET_ENTITY() */
-       dev->pmod_loc = pa_pdc_cell.mod_location;
+       dev->mod_info = pa_pdc_cell->mod_info;  /* pass to PAT_GET_ENTITY() */
+       dev->pmod_loc = pa_pdc_cell->mod_location;
 
        register_parisc_device(dev);    /* advertise device */
 
@@ -216,14 +220,14 @@ pat_query_module(ulong pcell_loc, ulong mod_index)
 
        case PAT_ENTITY_PROC:
                printk(KERN_DEBUG "PAT_ENTITY_PROC: id_eid 0x%lx\n",
-                       pa_pdc_cell.mod[0]);
+                       pa_pdc_cell->mod[0]);
                break;
 
        case PAT_ENTITY_MEM:
                printk(KERN_DEBUG 
                        "PAT_ENTITY_MEM: amount 0x%lx min_gni_base 0x%lx min_gni_len 0x%lx\n",
-                       pa_pdc_cell.mod[0], pa_pdc_cell.mod[1], 
-                       pa_pdc_cell.mod[2]);
+                       pa_pdc_cell->mod[0], pa_pdc_cell->mod[1],
+                       pa_pdc_cell->mod[2]);
                break;
        case PAT_ENTITY_CA:
                printk(KERN_DEBUG "PAT_ENTITY_CA: %ld\n", pcell_loc);
@@ -243,23 +247,26 @@ pat_query_module(ulong pcell_loc, ulong mod_index)
  print_ranges:
                pdc_pat_cell_module(&bytecnt, pcell_loc, mod_index,
                                    IO_VIEW, &io_pdc_cell);
-               printk(KERN_DEBUG "ranges %ld\n", pa_pdc_cell.mod[1]);
-               for (i = 0; i < pa_pdc_cell.mod[1]; i++) {
+               printk(KERN_DEBUG "ranges %ld\n", pa_pdc_cell->mod[1]);
+               for (i = 0; i < pa_pdc_cell->mod[1]; i++) {
                        printk(KERN_DEBUG 
                                "  PA_VIEW %ld: 0x%016lx 0x%016lx 0x%016lx\n", 
-                               i, pa_pdc_cell.mod[2 + i * 3],  /* type */
-                               pa_pdc_cell.mod[3 + i * 3],     /* start */
-                               pa_pdc_cell.mod[4 + i * 3]);    /* finish (ie end) */
+                               i, pa_pdc_cell->mod[2 + i * 3], /* type */
+                               pa_pdc_cell->mod[3 + i * 3],    /* start */
+                               pa_pdc_cell->mod[4 + i * 3]);   /* finish (ie end) */
                        printk(KERN_DEBUG 
                                "  IO_VIEW %ld: 0x%016lx 0x%016lx 0x%016lx\n", 
-                               i, io_pdc_cell.mod[2 + i * 3],  /* type */
-                               io_pdc_cell.mod[3 + i * 3],     /* start */
-                               io_pdc_cell.mod[4 + i * 3]);    /* finish (ie end) */
+                               i, io_pdc_cell->mod[2 + i * 3], /* type */
+                               io_pdc_cell->mod[3 + i * 3],    /* start */
+                               io_pdc_cell->mod[4 + i * 3]);   /* finish (ie end) */
                }
                printk(KERN_DEBUG "\n");
                break;
        }
 #endif /* DEBUG_PAT */
+
+       kfree(pa_pdc_cell);
+
        return PDC_OK;
 }
 
index 8007f1e..330f536 100644 (file)
@@ -120,7 +120,7 @@ int cpu_check_affinity(unsigned int irq, const struct cpumask *dest)
        if (CHECK_IRQ_PER_CPU(irq)) {
                /* Bad linux design decision.  The mask has already
                 * been set; we must reset it */
-               cpumask_setall(&irq_desc[irq].affinity);
+               cpumask_setall(irq_desc[irq].affinity);
                return -EINVAL;
        }
 
@@ -138,13 +138,13 @@ static int cpu_set_affinity_irq(unsigned int irq, const struct cpumask *dest)
        if (cpu_dest < 0)
                return -1;
 
-       cpumask_copy(&irq_desc[irq].affinity, dest);
+       cpumask_copy(irq_desc[irq].affinity, dest);
 
        return 0;
 }
 #endif
 
-static struct hw_interrupt_type cpu_interrupt_type = {
+static struct irq_chip cpu_interrupt_type = {
        .typename       = "CPU",
        .startup        = cpu_startup_irq,
        .shutdown       = cpu_disable_irq,
@@ -299,7 +299,7 @@ int txn_alloc_irq(unsigned int bits_wide)
 unsigned long txn_affinity_addr(unsigned int irq, int cpu)
 {
 #ifdef CONFIG_SMP
-       cpumask_copy(&irq_desc[irq].affinity, cpumask_of(cpu));
+       cpumask_copy(irq_desc[irq].affinity, cpumask_of(cpu));
 #endif
 
        return per_cpu(cpu_data, cpu).txn_addr;
@@ -356,7 +356,7 @@ void do_cpu_irq_mask(struct pt_regs *regs)
        irq = eirr_to_irq(eirr_val);
 
 #ifdef CONFIG_SMP
-       cpumask_copy(&dest, &irq_desc[irq].affinity);
+       cpumask_copy(&dest, irq_desc[irq].affinity);
        if (CHECK_IRQ_PER_CPU(irq_desc[irq].status) &&
            !cpu_isset(smp_processor_id(), dest)) {
                int cpu = first_cpu(dest);
index 7d927ea..c07f618 100644 (file)
@@ -90,12 +90,14 @@ static inline int map_pte_uncached(pte_t * pte,
        if (end > PMD_SIZE)
                end = PMD_SIZE;
        do {
+               unsigned long flags;
+
                if (!pte_none(*pte))
                        printk(KERN_ERR "map_pte_uncached: page already exists\n");
                set_pte(pte, __mk_pte(*paddr_ptr, PAGE_KERNEL_UNC));
-               purge_tlb_start();
+               purge_tlb_start(flags);
                pdtlb_kernel(orig_vaddr);
-               purge_tlb_end();
+               purge_tlb_end(flags);
                vaddr += PAGE_SIZE;
                orig_vaddr += PAGE_SIZE;
                (*paddr_ptr) += PAGE_SIZE;
@@ -168,11 +170,13 @@ static inline void unmap_uncached_pte(pmd_t * pmd, unsigned long vaddr,
        if (end > PMD_SIZE)
                end = PMD_SIZE;
        do {
+               unsigned long flags;
                pte_t page = *pte;
+
                pte_clear(&init_mm, vaddr, pte);
-               purge_tlb_start();
+               purge_tlb_start(flags);
                pdtlb_kernel(orig_vaddr);
-               purge_tlb_end();
+               purge_tlb_end(flags);
                vaddr += PAGE_SIZE;
                orig_vaddr += PAGE_SIZE;
                pte++;
index 6936386..f7064ab 100644 (file)
@@ -1,5 +1,4 @@
-/* $Id: pci.c,v 1.6 2000/01/29 00:12:05 grundler Exp $
- *
+/*
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
index e09d0f7..c8fb61e 100644 (file)
@@ -1,5 +1,4 @@
-/*    $Id: processor.c,v 1.1 2002/07/20 16:27:06 rhirst Exp $
- *
+/*
  *    Initial setup-routines for HP 9000 based hardware.
  *
  *    Copyright (C) 1991, 1992, 1995  Linus Torvalds
@@ -121,22 +120,28 @@ static int __cpuinit processor_probe(struct parisc_device *dev)
        if (is_pdc_pat()) {
                ulong status;
                unsigned long bytecnt;
-               pdc_pat_cell_mod_maddr_block_t pa_pdc_cell;
+               pdc_pat_cell_mod_maddr_block_t *pa_pdc_cell;
 #undef USE_PAT_CPUID
 #ifdef USE_PAT_CPUID
                struct pdc_pat_cpu_num cpu_info;
 #endif
 
+               pa_pdc_cell = kmalloc(sizeof (*pa_pdc_cell), GFP_KERNEL);
+               if (!pa_pdc_cell)
+                       panic("couldn't allocate memory for PDC_PAT_CELL!");
+
                status = pdc_pat_cell_module(&bytecnt, dev->pcell_loc,
-                       dev->mod_index, PA_VIEW, &pa_pdc_cell);
+                       dev->mod_index, PA_VIEW, pa_pdc_cell);
 
                BUG_ON(PDC_OK != status);
 
                /* verify it's the same as what do_pat_inventory() found */
-               BUG_ON(dev->mod_info != pa_pdc_cell.mod_info);
-               BUG_ON(dev->pmod_loc != pa_pdc_cell.mod_location);
+               BUG_ON(dev->mod_info != pa_pdc_cell->mod_info);
+               BUG_ON(dev->pmod_loc != pa_pdc_cell->mod_location);
+
+               txn_addr = pa_pdc_cell->mod[0];   /* id_eid for IO sapic */
 
-               txn_addr = pa_pdc_cell.mod[0];   /* id_eid for IO sapic */
+               kfree(pa_pdc_cell);
 
 #ifdef USE_PAT_CPUID
 /* We need contiguous numbers for cpuid. Firmware's notion
index 82131ca..cb71f3d 100644 (file)
@@ -1,5 +1,4 @@
-/*    $Id: setup.c,v 1.8 2000/02/02 04:42:38 prumpf Exp $
- *
+/*
  *    Initial setup-routines for HP 9000 based hardware.
  *
  *    Copyright (C) 1991, 1992, 1995  Linus Torvalds
index 1adb40c..92a0aca 100644 (file)
@@ -174,68 +174,6 @@ asmlinkage long sys32_sched_rr_get_interval(pid_t pid,
        return ret;
 }
 
-/*** copied from mips64 ***/
-/*
- * Ooo, nasty.  We need here to frob 32-bit unsigned longs to
- * 64-bit unsigned longs.
- */
-
-static inline int
-get_fd_set32(unsigned long n, u32 *ufdset, unsigned long *fdset)
-{
-       n = (n + 8*sizeof(u32) - 1) / (8*sizeof(u32));
-       if (ufdset) {
-               unsigned long odd;
-
-               if (!access_ok(VERIFY_WRITE, ufdset, n*sizeof(u32)))
-                       return -EFAULT;
-
-               odd = n & 1UL;
-               n &= ~1UL;
-               while (n) {
-                       unsigned long h, l;
-                       __get_user(l, ufdset);
-                       __get_user(h, ufdset+1);
-                       ufdset += 2;
-                       *fdset++ = h << 32 | l;
-                       n -= 2;
-               }
-               if (odd)
-                       __get_user(*fdset, ufdset);
-       } else {
-               /* Tricky, must clear full unsigned long in the
-                * kernel fdset at the end, this makes sure that
-                * actually happens.
-                */
-               memset(fdset, 0, ((n + 1) & ~1)*sizeof(u32));
-       }
-       return 0;
-}
-
-static inline void
-set_fd_set32(unsigned long n, u32 *ufdset, unsigned long *fdset)
-{
-       unsigned long odd;
-       n = (n + 8*sizeof(u32) - 1) / (8*sizeof(u32));
-
-       if (!ufdset)
-               return;
-
-       odd = n & 1UL;
-       n &= ~1UL;
-       while (n) {
-               unsigned long h, l;
-               l = *fdset++;
-               h = l >> 32;
-               __put_user(l, ufdset);
-               __put_user(h, ufdset+1);
-               ufdset += 2;
-               n -= 2;
-       }
-       if (odd)
-               __put_user(*fdset, ufdset);
-}
-
 struct msgbuf32 {
     int mtype;
     char mtext[1];
index 03b9a01..cf145eb 100644 (file)
        ENTRY_SAME(dup3)
        ENTRY_SAME(pipe2)
        ENTRY_SAME(inotify_init1)
+       ENTRY_COMP(preadv)              /* 315 */
+       ENTRY_COMP(pwritev)
+       ENTRY_COMP(rt_tgsigqueueinfo)
+       ENTRY_SAME(perf_counter_open)
 
        /* Nothing yet */
 
index d4dd056..a79c6f9 100644 (file)
@@ -56,9 +56,9 @@ static unsigned long clocktick __read_mostly; /* timer cycles per tick */
  */
 irqreturn_t __irq_entry timer_interrupt(int irq, void *dev_id)
 {
-       unsigned long now;
+       unsigned long now, now2;
        unsigned long next_tick;
-       unsigned long cycles_elapsed, ticks_elapsed;
+       unsigned long cycles_elapsed, ticks_elapsed = 1;
        unsigned long cycles_remainder;
        unsigned int cpu = smp_processor_id();
        struct cpuinfo_parisc *cpuinfo = &per_cpu(cpu_data, cpu);
@@ -71,44 +71,24 @@ irqreturn_t __irq_entry timer_interrupt(int irq, void *dev_id)
        /* Initialize next_tick to the expected tick time. */
        next_tick = cpuinfo->it_value;
 
-       /* Get current interval timer.
-        * CR16 reads as 64 bits in CPU wide mode.
-        * CR16 reads as 32 bits in CPU narrow mode.
-        */
+       /* Get current cycle counter (Control Register 16). */
        now = mfctl(16);
 
        cycles_elapsed = now - next_tick;
 
-       if ((cycles_elapsed >> 5) < cpt) {
+       if ((cycles_elapsed >> 6) < cpt) {
                /* use "cheap" math (add/subtract) instead
                 * of the more expensive div/mul method
                 */
                cycles_remainder = cycles_elapsed;
-               ticks_elapsed = 1;
                while (cycles_remainder > cpt) {
                        cycles_remainder -= cpt;
                        ticks_elapsed++;
                }
        } else {
+               /* TODO: Reduce this to one fdiv op */
                cycles_remainder = cycles_elapsed % cpt;
-               ticks_elapsed = 1 + cycles_elapsed / cpt;
-       }
-
-       /* Can we differentiate between "early CR16" (aka Scenario 1) and
-        * "long delay" (aka Scenario 3)? I don't think so.
-        *
-        * We expected timer_interrupt to be delivered at least a few hundred
-        * cycles after the IT fires. But it's arbitrary how much time passes
-        * before we call it "late". I've picked one second.
-        */
-       if (unlikely(ticks_elapsed > HZ)) {
-               /* Scenario 3: very long delay?  bad in any case */
-               printk (KERN_CRIT "timer_interrupt(CPU %d): delayed!"
-                       " cycles %lX rem %lX "
-                       " next/now %lX/%lX\n",
-                       cpu,
-                       cycles_elapsed, cycles_remainder,
-                       next_tick, now );
+               ticks_elapsed += cycles_elapsed / cpt;
        }
 
        /* convert from "division remainder" to "remainder of clock tick" */
@@ -122,18 +102,56 @@ irqreturn_t __irq_entry timer_interrupt(int irq, void *dev_id)
 
        cpuinfo->it_value = next_tick;
 
-       /* Skip one clocktick on purpose if we are likely to miss next_tick.
-        * We want to avoid the new next_tick being less than CR16.
-        * If that happened, itimer wouldn't fire until CR16 wrapped.
-        * We'll catch the tick we missed on the tick after that.
+       /* Program the IT when to deliver the next interrupt.
+        * Only bottom 32-bits of next_tick are writable in CR16!
         */
-       if (!(cycles_remainder >> 13))
-               next_tick += cpt;
-
-       /* Program the IT when to deliver the next interrupt. */
-       /* Only bottom 32-bits of next_tick are written to cr16.  */
        mtctl(next_tick, 16);
 
+       /* Skip one clocktick on purpose if we missed next_tick.
+        * The new CR16 must be "later" than current CR16 otherwise
+        * itimer would not fire until CR16 wrapped - e.g 4 seconds
+        * later on a 1Ghz processor. We'll account for the missed
+        * tick on the next timer interrupt.
+        *
+        * "next_tick - now" will always give the difference regardless
+        * if one or the other wrapped. If "now" is "bigger" we'll end up
+        * with a very large unsigned number.
+        */
+       now2 = mfctl(16);
+       if (next_tick - now2 > cpt)
+               mtctl(next_tick+cpt, 16);
+
+#if 1
+/*
+ * GGG: DEBUG code for how many cycles programming CR16 used.
+ */
+       if (unlikely(now2 - now > 0x3000))      /* 12K cycles */
+               printk (KERN_CRIT "timer_interrupt(CPU %d): SLOW! 0x%lx cycles!"
+                       " cyc %lX rem %lX "
+                       " next/now %lX/%lX\n",
+                       cpu, now2 - now, cycles_elapsed, cycles_remainder,
+                       next_tick, now );
+#endif
+
+       /* Can we differentiate between "early CR16" (aka Scenario 1) and
+        * "long delay" (aka Scenario 3)? I don't think so.
+        *
+        * Timer_interrupt will be delivered at least a few hundred cycles
+        * after the IT fires. But it's arbitrary how much time passes
+        * before we call it "late". I've picked one second.
+        *
+        * It's important NO printk's are between reading CR16 and
+        * setting up the next value. May introduce huge variance.
+        */
+       if (unlikely(ticks_elapsed > HZ)) {
+               /* Scenario 3: very long delay?  bad in any case */
+               printk (KERN_CRIT "timer_interrupt(CPU %d): delayed!"
+                       " cycles %lX rem %lX "
+                       " next/now %lX/%lX\n",
+                       cpu,
+                       cycles_elapsed, cycles_remainder,
+                       next_tick, now );
+       }
 
        /* Done mucking with unreliable delivery of interrupts.
         * Go do system house keeping.
@@ -173,7 +191,7 @@ EXPORT_SYMBOL(profile_pc);
 
 /* clock source code */
 
-static cycle_t read_cr16(void)
+static cycle_t read_cr16(struct clocksource *cs)
 {
        return get_cycles();
 }
index 462696d..ae66d31 100644 (file)
@@ -13,8 +13,6 @@
  *             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.
- *
- * $Id: checksum.c,v 1.3 1997/12/01 17:57:34 ralf Exp $
  */
 #include <linux/module.h>
 #include <linux/types.h>
index bbda909..abf41f4 100644 (file)
@@ -405,7 +405,7 @@ byte_copy:
 
 unaligned_copy:
        /* possibly we are aligned on a word, but not on a double... */
-       if (likely(t1 & (sizeof(unsigned int)-1)) == 0) {
+       if (likely((t1 & (sizeof(unsigned int)-1)) == 0)) {
                t2 = src & (sizeof(unsigned int) - 1);
 
                if (unlikely(t2 != 0)) {
index 66c8a9f..3ca1c61 100644 (file)
@@ -40,7 +40,7 @@
  * END_DESC
 */
 
-
+#include <linux/kernel.h>
 #include "float.h"
 #include "sgl_float.h"
 #include "dbl_float.h"
index bfb6dd6..c6afbfc 100644 (file)
@@ -1,5 +1,4 @@
-/* $Id: fault.c,v 1.5 2000/01/26 16:20:29 jsm Exp $
- *
+/*
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
index 4356ceb..b0831d9 100644 (file)
@@ -370,34 +370,22 @@ static void __init setup_bootmem(void)
 
 void free_initmem(void)
 {
-       unsigned long addr, init_begin, init_end;
-
-       printk(KERN_INFO "Freeing unused kernel memory: ");
+       unsigned long addr;
+       unsigned long init_begin = (unsigned long)__init_begin;
+       unsigned long init_end = (unsigned long)__init_end;
 
 #ifdef CONFIG_DEBUG_KERNEL
        /* Attempt to catch anyone trying to execute code here
         * by filling the page with BRK insns.
-        * 
-        * If we disable interrupts for all CPUs, then IPI stops working.
-        * Kinda breaks the global cache flushing.
         */
-       local_irq_disable();
-
-       memset(__init_begin, 0x00,
-               (unsigned long)__init_end - (unsigned long)__init_begin);
-
-       flush_data_cache();
-       asm volatile("sync" : : );
-       flush_icache_range((unsigned long)__init_begin, (unsigned long)__init_end);
-       asm volatile("sync" : : );
-
-       local_irq_enable();
+       memset((void *)init_begin, 0x00, init_end - init_begin);
+       flush_icache_range(init_begin, init_end);
 #endif
        
        /* align __init_begin and __init_end to page size,
           ignoring linker script where we might have tried to save RAM */
-       init_begin = PAGE_ALIGN((unsigned long)(__init_begin));
-       init_end   = PAGE_ALIGN((unsigned long)(__init_end));
+       init_begin = PAGE_ALIGN(init_begin);
+       init_end = PAGE_ALIGN(init_end);
        for (addr = init_begin; addr < init_end; addr += PAGE_SIZE) {
                ClearPageReserved(virt_to_page(addr));
                init_page_count(virt_to_page(addr));
@@ -409,7 +397,8 @@ void free_initmem(void)
        /* set up a new led state on systems shipped LED State panel */
        pdc_chassis_send_status(PDC_CHASSIS_DIRECT_BCOMPLETE);
        
-       printk("%luk freed\n", (init_end - init_begin) >> 10);
+       printk(KERN_INFO "Freeing unused kernel memory: %luk freed\n",
+               (init_end - init_begin) >> 10);
 }
 
 
index bf6cedf..d00131c 100644 (file)
@@ -62,7 +62,6 @@ config HAVE_LATENCYTOP_SUPPORT
 
 config TRACE_IRQFLAGS_SUPPORT
        bool
-       depends on PPC64
        default y
 
 config LOCKDEP_SUPPORT
index 2f50acd..3d80c3e 100644 (file)
@@ -36,3 +36,13 @@ zImage.pseries
 zconf.h
 zlib.h
 zutil.h
+fdt.c
+fdt.h
+fdt_ro.c
+fdt_rw.c
+fdt_strerror.c
+fdt_sw.c
+fdt_wip.c
+libfdt.h
+libfdt_internal.h
+
index 26549fc..49ac36b 100644 (file)
@@ -70,8 +70,8 @@
                        devsel-speed = <0x00000001>;
                        min-grant = <0>;
                        max-latency = <0>;
-                       /* First 64k for I/O at 0x0 on PCI mapped to 0x0 on ISA. */
-                       ranges = <0x00000001 0 0x01000000 0 0x00000000 0x00010000>;
+                       /* First 4k for I/O at 0x0 on PCI mapped to 0x0 on ISA. */
+                       ranges = <0x00000001 0 0x01000000 0 0x00000000 0x00001000>;
                        interrupt-parent = <&i8259>;
                        #interrupt-cells = <2>;
                        #address-cells = <2>;
index a8dcb01..a680165 100644 (file)
                        /* Filled in by U-Boot */
                        clock-frequency = <0>;
                        status = "disabled";
+                       sdhci,1-bit-only;
                };
 
                crypto@30000 {
index 2ff7987..7685ffd 100644 (file)
@@ -598,8 +598,6 @@ typedef struct risc_timer_pram {
 #define CICR_IEN               ((uint)0x00000080)      /* Int. enable */
 #define CICR_SPS               ((uint)0x00000001)      /* SCC Spread */
 
-#define IMAP_ADDR              (get_immrbase())
-
 #define CPM_PIN_INPUT     0
 #define CPM_PIN_OUTPUT    1
 #define CPM_PIN_PRIMARY   0
index 3d9e887..b44aaab 100644 (file)
@@ -309,7 +309,9 @@ static inline void dma_sync_single_for_cpu(struct device *dev,
        struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
 
        BUG_ON(!dma_ops);
-       dma_ops->sync_single_range_for_cpu(dev, dma_handle, 0,
+
+       if (dma_ops->sync_single_range_for_cpu)
+               dma_ops->sync_single_range_for_cpu(dev, dma_handle, 0,
                                           size, direction);
 }
 
@@ -320,7 +322,9 @@ static inline void dma_sync_single_for_device(struct device *dev,
        struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
 
        BUG_ON(!dma_ops);
-       dma_ops->sync_single_range_for_device(dev, dma_handle,
+
+       if (dma_ops->sync_single_range_for_device)
+               dma_ops->sync_single_range_for_device(dev, dma_handle,
                                              0, size, direction);
 }
 
@@ -331,7 +335,9 @@ static inline void dma_sync_sg_for_cpu(struct device *dev,
        struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
 
        BUG_ON(!dma_ops);
-       dma_ops->sync_sg_for_cpu(dev, sgl, nents, direction);
+
+       if (dma_ops->sync_sg_for_cpu)
+               dma_ops->sync_sg_for_cpu(dev, sgl, nents, direction);
 }
 
 static inline void dma_sync_sg_for_device(struct device *dev,
@@ -341,7 +347,9 @@ static inline void dma_sync_sg_for_device(struct device *dev,
        struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
 
        BUG_ON(!dma_ops);
-       dma_ops->sync_sg_for_device(dev, sgl, nents, direction);
+
+       if (dma_ops->sync_sg_for_device)
+               dma_ops->sync_sg_for_device(dev, sgl, nents, direction);
 }
 
 static inline void dma_sync_single_range_for_cpu(struct device *dev,
@@ -351,7 +359,9 @@ static inline void dma_sync_single_range_for_cpu(struct device *dev,
        struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
 
        BUG_ON(!dma_ops);
-       dma_ops->sync_single_range_for_cpu(dev, dma_handle,
+
+       if (dma_ops->sync_single_range_for_cpu)
+               dma_ops->sync_single_range_for_cpu(dev, dma_handle,
                                           offset, size, direction);
 }
 
@@ -362,7 +372,9 @@ static inline void dma_sync_single_range_for_device(struct device *dev,
        struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
 
        BUG_ON(!dma_ops);
-       dma_ops->sync_single_range_for_device(dev, dma_handle, offset,
+
+       if (dma_ops->sync_single_range_for_device)
+               dma_ops->sync_single_range_for_device(dev, dma_handle, offset,
                                              size, direction);
 }
 #else /* CONFIG_PPC_NEED_DMA_SYNC_OPS */
index 684a73f..a74c4ee 100644 (file)
@@ -22,9 +22,7 @@
 
 #ifdef __KERNEL__
 
-#include <linux/init.h>
 #include <linux/interrupt.h>
-#include <linux/highmem.h>
 #include <asm/kmap_types.h>
 #include <asm/tlbflush.h>
 #include <asm/page.h>
@@ -62,6 +60,9 @@ extern pte_t *pkmap_page_table;
 
 extern void *kmap_high(struct page *page);
 extern void kunmap_high(struct page *page);
+extern void *kmap_atomic_prot(struct page *page, enum km_type type,
+                             pgprot_t prot);
+extern void kunmap_atomic(void *kvaddr, enum km_type type);
 
 static inline void *kmap(struct page *page)
 {
@@ -79,62 +80,11 @@ static inline void kunmap(struct page *page)
        kunmap_high(page);
 }
 
-/*
- * The use of kmap_atomic/kunmap_atomic is discouraged - kmap/kunmap
- * gives a more generic (and caching) interface. But kmap_atomic can
- * be used in IRQ contexts, so in some (very limited) cases we need
- * it.
- */
-static inline void *kmap_atomic_prot(struct page *page, enum km_type type, pgprot_t prot)
-{
-       unsigned int idx;
-       unsigned long vaddr;
-
-       /* even !CONFIG_PREEMPT needs this, for in_atomic in do_page_fault */
-       pagefault_disable();
-       if (!PageHighMem(page))
-               return page_address(page);
-
-       debug_kmap_atomic(type);
-       idx = type + KM_TYPE_NR*smp_processor_id();
-       vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
-#ifdef CONFIG_DEBUG_HIGHMEM
-       BUG_ON(!pte_none(*(kmap_pte-idx)));
-#endif
-       __set_pte_at(&init_mm, vaddr, kmap_pte-idx, mk_pte(page, prot), 1);
-       local_flush_tlb_page(NULL, vaddr);
-
-       return (void*) vaddr;
-}
-
 static inline void *kmap_atomic(struct page *page, enum km_type type)
 {
        return kmap_atomic_prot(page, type, kmap_prot);
 }
 
-static inline void kunmap_atomic(void *kvaddr, enum km_type type)
-{
-#ifdef CONFIG_DEBUG_HIGHMEM
-       unsigned long vaddr = (unsigned long) kvaddr & PAGE_MASK;
-       enum fixed_addresses idx = type + KM_TYPE_NR*smp_processor_id();
-
-       if (vaddr < __fix_to_virt(FIX_KMAP_END)) {
-               pagefault_enable();
-               return;
-       }
-
-       BUG_ON(vaddr != __fix_to_virt(FIX_KMAP_BEGIN + idx));
-
-       /*
-        * force other mappings to Oops if they'll try to access
-        * this pte without first remap it
-        */
-       pte_clear(&init_mm, vaddr, kmap_pte-idx);
-       local_flush_tlb_page(NULL, vaddr);
-#endif
-       pagefault_enable();
-}
-
 static inline struct page *kmap_atomic_to_page(void *ptr)
 {
        unsigned long idx, vaddr = (unsigned long) ptr;
@@ -148,6 +98,7 @@ static inline struct page *kmap_atomic_to_page(void *ptr)
        return pte_page(*pte);
 }
 
+
 #define flush_cache_kmaps()    flush_cache_all()
 
 #endif /* __KERNEL__ */
index 867ab8e..8b505ea 100644 (file)
@@ -68,13 +68,13 @@ static inline int irqs_disabled_flags(unsigned long flags)
 
 #if defined(CONFIG_BOOKE)
 #define SET_MSR_EE(x)  mtmsr(x)
-#define local_irq_restore(flags)       __asm__ __volatile__("wrtee %0" : : "r" (flags) : "memory")
+#define raw_local_irq_restore(flags)   __asm__ __volatile__("wrtee %0" : : "r" (flags) : "memory")
 #else
 #define SET_MSR_EE(x)  mtmsr(x)
-#define local_irq_restore(flags)       mtmsr(flags)
+#define raw_local_irq_restore(flags)   mtmsr(flags)
 #endif
 
-static inline void local_irq_disable(void)
+static inline void raw_local_irq_disable(void)
 {
 #ifdef CONFIG_BOOKE
        __asm__ __volatile__("wrteei 0": : :"memory");
@@ -86,7 +86,7 @@ static inline void local_irq_disable(void)
 #endif
 }
 
-static inline void local_irq_enable(void)
+static inline void raw_local_irq_enable(void)
 {
 #ifdef CONFIG_BOOKE
        __asm__ __volatile__("wrteei 1": : :"memory");
@@ -98,7 +98,7 @@ static inline void local_irq_enable(void)
 #endif
 }
 
-static inline void local_irq_save_ptr(unsigned long *flags)
+static inline void raw_local_irq_save_ptr(unsigned long *flags)
 {
        unsigned long msr;
        msr = mfmsr();
@@ -110,12 +110,12 @@ static inline void local_irq_save_ptr(unsigned long *flags)
 #endif
 }
 
-#define local_save_flags(flags)        ((flags) = mfmsr())
-#define local_irq_save(flags)  local_irq_save_ptr(&flags)
-#define irqs_disabled()                ((mfmsr() & MSR_EE) == 0)
+#define raw_local_save_flags(flags)    ((flags) = mfmsr())
+#define raw_local_irq_save(flags)      raw_local_irq_save_ptr(&flags)
+#define raw_irqs_disabled()            ((mfmsr() & MSR_EE) == 0)
+#define raw_irqs_disabled_flags(flags) (((flags) & MSR_EE) == 0)
 
-#define hard_irq_enable()      local_irq_enable()
-#define hard_irq_disable()     local_irq_disable()
+#define hard_irq_disable()             raw_local_irq_disable()
 
 static inline int irqs_disabled_flags(unsigned long flags)
 {
index 8ccd4e1..0ea0639 100644 (file)
@@ -61,6 +61,8 @@ struct pt_regs;
 extern unsigned long perf_misc_flags(struct pt_regs *regs);
 extern unsigned long perf_instruction_pointer(struct pt_regs *regs);
 
+#define PERF_COUNTER_INDEX_OFFSET      1
+
 /*
  * Only override the default definitions in include/linux/perf_counter.h
  * if we have hardware PMU support.
index e05d26f..82b7220 100644 (file)
@@ -47,7 +47,8 @@
  * generic accessors and iterators here
  */
 #define __real_pte(e,p)        ((real_pte_t) { \
-       (e), pte_val(*((p) + PTRS_PER_PTE)) })
+                       (e), ((e) & _PAGE_COMBO) ? \
+                               (pte_val(*((p) + PTRS_PER_PTE))) : 0 })
 #define __rpte_to_hidx(r,index)        ((pte_val((r).pte) & _PAGE_COMBO) ? \
         (((r).hidx >> ((index)<<2)) & 0xf) : ((pte_val((r).pte) >> 12) & 0xf))
 #define __rpte_to_pte(r)       ((r).pte)
index 01c1233..168fce7 100644 (file)
@@ -58,7 +58,7 @@ struct rtas_t {
        unsigned long entry;            /* physical address pointer */
        unsigned long base;             /* physical address pointer */
        unsigned long size;
-       spinlock_t lock;
+       raw_spinlock_t lock;
        struct rtas_args args;
        struct device_node *dev;        /* virtual address pointer */
 };
@@ -245,5 +245,8 @@ static inline u32 rtas_config_addr(int busno, int devfn, int reg)
                        (devfn << 8) | (reg & 0xff);
 }
 
+extern void __cpuinit rtas_give_timebase(void);
+extern void __cpuinit rtas_take_timebase(void);
+
 #endif /* __KERNEL__ */
 #endif /* _POWERPC_RTAS_H */
index 4dd38f1..3cadba6 100644 (file)
@@ -191,11 +191,49 @@ transfer_to_handler_cont:
        mflr    r9
        lwz     r11,0(r9)               /* virtual address of handler */
        lwz     r9,4(r9)                /* where to go when done */
+#ifdef CONFIG_TRACE_IRQFLAGS
+       lis     r12,reenable_mmu@h
+       ori     r12,r12,reenable_mmu@l
+       mtspr   SPRN_SRR0,r12
+       mtspr   SPRN_SRR1,r10
+       SYNC
+       RFI
+reenable_mmu:                          /* re-enable mmu so we can */
+       mfmsr   r10
+       lwz     r12,_MSR(r1)
+       xor     r10,r10,r12
+       andi.   r10,r10,MSR_EE          /* Did EE change? */
+       beq     1f
+
+       /* Save handler and return address into the 2 unused words
+        * of the STACK_FRAME_OVERHEAD (sneak sneak sneak). Everything
+        * else can be recovered from the pt_regs except r3 which for
+        * normal interrupts has been set to pt_regs and for syscalls
+        * is an argument, so we temporarily use ORIG_GPR3 to save it
+        */
+       stw     r9,8(r1)
+       stw     r11,12(r1)
+       stw     r3,ORIG_GPR3(r1)
+       bl      trace_hardirqs_off
+       lwz     r0,GPR0(r1)
+       lwz     r3,ORIG_GPR3(r1)
+       lwz     r4,GPR4(r1)
+       lwz     r5,GPR5(r1)
+       lwz     r6,GPR6(r1)
+       lwz     r7,GPR7(r1)
+       lwz     r8,GPR8(r1)
+       lwz     r9,8(r1)
+       lwz     r11,12(r1)
+1:     mtctr   r11
+       mtlr    r9
+       bctr                            /* jump to handler */
+#else /* CONFIG_TRACE_IRQFLAGS */
        mtspr   SPRN_SRR0,r11
        mtspr   SPRN_SRR1,r10
        mtlr    r9
        SYNC
        RFI                             /* jump to handler, enable MMU */
+#endif /* CONFIG_TRACE_IRQFLAGS */
 
 #if defined (CONFIG_6xx) || defined(CONFIG_E500)
 4:     rlwinm  r12,r12,0,~_TLF_NAPPING
@@ -251,6 +289,31 @@ _GLOBAL(DoSyscall)
 #ifdef SHOW_SYSCALLS
        bl      do_show_syscall
 #endif /* SHOW_SYSCALLS */
+#ifdef CONFIG_TRACE_IRQFLAGS
+       /* Return from syscalls can (and generally will) hard enable
+        * interrupts. You aren't supposed to call a syscall with
+        * interrupts disabled in the first place. However, to ensure
+        * that we get it right vs. lockdep if it happens, we force
+        * that hard enable here with appropriate tracing if we see
+        * that we have been called with interrupts off
+        */
+       mfmsr   r11
+       andi.   r12,r11,MSR_EE
+       bne+    1f
+       /* We came in with interrupts disabled, we enable them now */
+       bl      trace_hardirqs_on
+       mfmsr   r11
+       lwz     r0,GPR0(r1)
+       lwz     r3,GPR3(r1)
+       lwz     r4,GPR4(r1)
+       ori     r11,r11,MSR_EE
+       lwz     r5,GPR5(r1)
+       lwz     r6,GPR6(r1)
+       lwz     r7,GPR7(r1)
+       lwz     r8,GPR8(r1)
+       mtmsr   r11
+1:
+#endif /* CONFIG_TRACE_IRQFLAGS */
        rlwinm  r10,r1,0,0,(31-THREAD_SHIFT)    /* current_thread_info() */
        lwz     r11,TI_FLAGS(r10)
        andi.   r11,r11,_TIF_SYSCALL_T_OR_A
@@ -275,6 +338,7 @@ ret_from_syscall:
        rlwinm  r12,r1,0,0,(31-THREAD_SHIFT)    /* current_thread_info() */
        /* disable interrupts so current_thread_info()->flags can't change */
        LOAD_MSR_KERNEL(r10,MSR_KERNEL) /* doesn't include MSR_EE */
+       /* Note: We don't bother telling lockdep about it */
        SYNC
        MTMSRD(r10)
        lwz     r9,TI_FLAGS(r12)
@@ -288,6 +352,19 @@ ret_from_syscall:
        oris    r11,r11,0x1000  /* Set SO bit in CR */
        stw     r11,_CCR(r1)
 syscall_exit_cont:
+       lwz     r8,_MSR(r1)
+#ifdef CONFIG_TRACE_IRQFLAGS
+       /* If we are going to return from the syscall with interrupts
+        * off, we trace that here. It shouldn't happen though but we
+        * want to catch the bugger if it does right ?
+        */
+       andi.   r10,r8,MSR_EE
+       bne+    1f
+       stw     r3,GPR3(r1)
+       bl      trace_hardirqs_off
+       lwz     r3,GPR3(r1)
+1:
+#endif /* CONFIG_TRACE_IRQFLAGS */
 #if defined(CONFIG_4xx) || defined(CONFIG_BOOKE)
        /* If the process has its own DBCR0 value, load it up.  The internal
           debug mode bit tells us that dbcr0 should be loaded. */
@@ -311,7 +388,6 @@ END_FTR_SECTION_IFSET(CPU_FTR_NEED_PAIRED_STWCX)
        mtlr    r4
        mtcr    r5
        lwz     r7,_NIP(r1)
-       lwz     r8,_MSR(r1)
        FIX_SRR1(r8, r0)
        lwz     r2,GPR2(r1)
        lwz     r1,GPR1(r1)
@@ -394,7 +470,9 @@ syscall_exit_work:
        andi.   r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP)
        beq     ret_from_except
 
-       /* Re-enable interrupts */
+       /* Re-enable interrupts. There is no need to trace that with
+        * lockdep as we are supposed to have IRQs on at this point
+        */
        ori     r10,r10,MSR_EE
        SYNC
        MTMSRD(r10)
@@ -705,6 +783,7 @@ ret_from_except:
        /* Hard-disable interrupts so that current_thread_info()->flags
         * can't change between when we test it and when we return
         * from the interrupt. */
+       /* Note: We don't bother telling lockdep about it */
        LOAD_MSR_KERNEL(r10,MSR_KERNEL)
        SYNC                    /* Some chip revs have problems here... */
        MTMSRD(r10)             /* disable interrupts */
@@ -744,11 +823,24 @@ resume_kernel:
        beq+    restore
        andi.   r0,r3,MSR_EE    /* interrupts off? */
        beq     restore         /* don't schedule if so */
+#ifdef CONFIG_TRACE_IRQFLAGS
+       /* Lockdep thinks irqs are enabled, we need to call
+        * preempt_schedule_irq with IRQs off, so we inform lockdep
+        * now that we -did- turn them off already
+        */
+       bl      trace_hardirqs_off
+#endif
 1:     bl      preempt_schedule_irq
        rlwinm  r9,r1,0,0,(31-THREAD_SHIFT)
        lwz     r3,TI_FLAGS(r9)
        andi.   r0,r3,_TIF_NEED_RESCHED
        bne-    1b
+#ifdef CONFIG_TRACE_IRQFLAGS
+       /* And now, to properly rebalance the above, we tell lockdep they
+        * are being turned back on, which will happen when we return
+        */
+       bl      trace_hardirqs_on
+#endif
 #else
 resume_kernel:
 #endif /* CONFIG_PREEMPT */
@@ -765,6 +857,28 @@ restore:
        stw     r6,icache_44x_need_flush@l(r4)
 1:
 #endif  /* CONFIG_44x */
+
+       lwz     r9,_MSR(r1)
+#ifdef CONFIG_TRACE_IRQFLAGS
+       /* Lockdep doesn't know about the fact that IRQs are temporarily turned
+        * off in this assembly code while peeking at TI_FLAGS() and such. However
+        * we need to inform it if the exception turned interrupts off, and we
+        * are about to trun them back on.
+        *
+        * The problem here sadly is that we don't know whether the exceptions was
+        * one that turned interrupts off or not. So we always tell lockdep about
+        * turning them on here when we go back to wherever we came from with EE
+        * on, even if that may meen some redudant calls being tracked. Maybe later
+        * we could encode what the exception did somewhere or test the exception
+        * type in the pt_regs but that sounds overkill
+        */
+       andi.   r10,r9,MSR_EE
+       beq     1f
+       bl      trace_hardirqs_on
+       lwz     r9,_MSR(r1)
+1:
+#endif /* CONFIG_TRACE_IRQFLAGS */
+
        lwz     r0,GPR0(r1)
        lwz     r2,GPR2(r1)
        REST_4GPRS(3, r1)
@@ -782,7 +896,6 @@ END_FTR_SECTION_IFSET(CPU_FTR_NEED_PAIRED_STWCX)
        stwcx.  r0,0,r1                 /* to clear the reservation */
 
 #if !(defined(CONFIG_4xx) || defined(CONFIG_BOOKE))
-       lwz     r9,_MSR(r1)
        andi.   r10,r9,MSR_RI           /* check if this exception occurred */
        beql    nonrecoverable          /* at a bad place (MSR:RI = 0) */
 
@@ -805,7 +918,6 @@ END_FTR_SECTION_IFSET(CPU_FTR_NEED_PAIRED_STWCX)
        MTMSRD(r10)             /* clear the RI bit */
        .globl exc_exit_restart
 exc_exit_restart:
-       lwz     r9,_MSR(r1)
        lwz     r12,_NIP(r1)
        FIX_SRR1(r9,r10)
        mtspr   SPRN_SRR0,r12
@@ -1035,11 +1147,18 @@ do_work:                        /* r10 contains MSR_KERNEL here */
        beq     do_user_signal
 
 do_resched:                    /* r10 contains MSR_KERNEL here */
+       /* Note: We don't need to inform lockdep that we are enabling
+        * interrupts here. As far as it knows, they are already enabled
+        */
        ori     r10,r10,MSR_EE
        SYNC
        MTMSRD(r10)             /* hard-enable interrupts */
        bl      schedule
 recheck:
+       /* Note: And we don't tell it we are disabling them again
+        * neither. Those disable/enable cycles used to peek at
+        * TI_FLAGS aren't advertised.
+        */
        LOAD_MSR_KERNEL(r10,MSR_KERNEL)
        SYNC
        MTMSRD(r10)             /* disable interrupts */
index 4846946..fc21329 100644 (file)
@@ -1124,9 +1124,8 @@ mmu_off:
        RFI
 
 /*
- * Use the first pair of BAT registers to map the 1st 16MB
- * of RAM to PAGE_OFFSET.  From this point on we can't safely
- * call OF any more.
+ * On 601, we use 3 BATs to map up to 24M of RAM at _PAGE_OFFSET
+ * (we keep one for debugging) and on others, we use one 256M BAT.
  */
 initial_bats:
        lis     r11,PAGE_OFFSET@h
@@ -1136,12 +1135,16 @@ initial_bats:
        bne     4f
        ori     r11,r11,4               /* set up BAT registers for 601 */
        li      r8,0x7f                 /* valid, block length = 8MB */
-       oris    r9,r11,0x800000@h       /* set up BAT reg for 2nd 8M */
-       oris    r10,r8,0x800000@h       /* set up BAT reg for 2nd 8M */
        mtspr   SPRN_IBAT0U,r11         /* N.B. 601 has valid bit in */
        mtspr   SPRN_IBAT0L,r8          /* lower BAT register */
-       mtspr   SPRN_IBAT1U,r9
-       mtspr   SPRN_IBAT1L,r10
+       addis   r11,r11,0x800000@h
+       addis   r8,r8,0x800000@h
+       mtspr   SPRN_IBAT1U,r11
+       mtspr   SPRN_IBAT1L,r8
+       addis   r11,r11,0x800000@h
+       addis   r8,r8,0x800000@h
+       mtspr   SPRN_IBAT2U,r11
+       mtspr   SPRN_IBAT2L,r8
        isync
        blr
 
index fa983a5..a359cb0 100644 (file)
@@ -76,7 +76,7 @@ struct of_device *of_device_alloc(struct device_node *np,
        dev->dev.archdata.of_node = np;
 
        if (bus_id)
-               dev_set_name(&dev->dev, bus_id);
+               dev_set_name(&dev->dev, "%s", bus_id);
        else
                of_device_make_bus_id(dev);
 
index 3e7135b..892a9f2 100644 (file)
@@ -528,7 +528,7 @@ void show_regs(struct pt_regs * regs)
 
        for (i = 0;  i < 32;  i++) {
                if ((i % REGS_PER_LINE) == 0)
-                       printk("\n" KERN_INFO "GPR%02d: ", i);
+                       printk("\nGPR%02d: ", i);
                printk(REG " ", regs->gpr[i]);
                if (i == LAST_VOLATILE && !FULL_REGS(regs))
                        break;
index ee4c760..c434823 100644 (file)
 #include <asm/syscalls.h>
 #include <asm/smp.h>
 #include <asm/atomic.h>
+#include <asm/time.h>
 
 struct rtas_t rtas = {
-       .lock = SPIN_LOCK_UNLOCKED
+       .lock = __RAW_SPIN_LOCK_UNLOCKED
 };
 EXPORT_SYMBOL(rtas);
 
@@ -67,6 +68,28 @@ unsigned long rtas_rmo_buf;
 void (*rtas_flash_term_hook)(int);
 EXPORT_SYMBOL(rtas_flash_term_hook);
 
+/* RTAS use home made raw locking instead of spin_lock_irqsave
+ * because those can be called from within really nasty contexts
+ * such as having the timebase stopped which would lockup with
+ * normal locks and spinlock debugging enabled
+ */
+static unsigned long lock_rtas(void)
+{
+       unsigned long flags;
+
+       local_irq_save(flags);
+       preempt_disable();
+       __raw_spin_lock_flags(&rtas.lock, flags);
+       return flags;
+}
+
+static void unlock_rtas(unsigned long flags)
+{
+       __raw_spin_unlock(&rtas.lock);
+       local_irq_restore(flags);
+       preempt_enable();
+}
+
 /*
  * call_rtas_display_status and call_rtas_display_status_delay
  * are designed only for very early low-level debugging, which
@@ -79,7 +102,7 @@ static void call_rtas_display_status(char c)
 
        if (!rtas.base)
                return;
-       spin_lock_irqsave(&rtas.lock, s);
+       s = lock_rtas();
 
        args->token = 10;
        args->nargs = 1;
@@ -89,7 +112,7 @@ static void call_rtas_display_status(char c)
 
        enter_rtas(__pa(args));
 
-       spin_unlock_irqrestore(&rtas.lock, s);
+       unlock_rtas(s);
 }
 
 static void call_rtas_display_status_delay(char c)
@@ -411,8 +434,7 @@ int rtas_call(int token, int nargs, int nret, int *outputs, ...)
        if (!rtas.entry || token == RTAS_UNKNOWN_SERVICE)
                return -1;
 
-       /* Gotta do something different here, use global lock for now... */
-       spin_lock_irqsave(&rtas.lock, s);
+       s = lock_rtas();
        rtas_args = &rtas.args;
 
        rtas_args->token = token;
@@ -439,8 +461,7 @@ int rtas_call(int token, int nargs, int nret, int *outputs, ...)
                        outputs[i] = rtas_args->rets[i+1];
        ret = (nret > 0)? rtas_args->rets[0]: 0;
 
-       /* Gotta do something different here, use global lock for now... */
-       spin_unlock_irqrestore(&rtas.lock, s);
+       unlock_rtas(s);
 
        if (buff_copy) {
                log_error(buff_copy, ERR_TYPE_RTAS_LOG, 0);
@@ -837,7 +858,7 @@ asmlinkage int ppc_rtas(struct rtas_args __user *uargs)
 
        buff_copy = get_errorlog_buffer();
 
-       spin_lock_irqsave(&rtas.lock, flags);
+       flags = lock_rtas();
 
        rtas.args = args;
        enter_rtas(__pa(&rtas.args));
@@ -848,7 +869,7 @@ asmlinkage int ppc_rtas(struct rtas_args __user *uargs)
        if (args.rets[0] == -1)
                errbuf = __fetch_rtas_last_error(buff_copy);
 
-       spin_unlock_irqrestore(&rtas.lock, flags);
+       unlock_rtas(flags);
 
        if (buff_copy) {
                if (errbuf)
@@ -951,3 +972,33 @@ int __init early_init_dt_scan_rtas(unsigned long node,
        /* break now */
        return 1;
 }
+
+static raw_spinlock_t timebase_lock;
+static u64 timebase = 0;
+
+void __cpuinit rtas_give_timebase(void)
+{
+       unsigned long flags;
+
+       local_irq_save(flags);
+       hard_irq_disable();
+       __raw_spin_lock(&timebase_lock);
+       rtas_call(rtas_token("freeze-time-base"), 0, 1, NULL);
+       timebase = get_tb();
+       __raw_spin_unlock(&timebase_lock);
+
+       while (timebase)
+               barrier();
+       rtas_call(rtas_token("thaw-time-base"), 0, 1, NULL);
+       local_irq_restore(flags);
+}
+
+void __cpuinit rtas_take_timebase(void)
+{
+       while (!timebase)
+               barrier();
+       __raw_spin_lock(&timebase_lock);
+       set_tb(timebase >> 32, timebase & 0xffffffff);
+       timebase = 0;
+       __raw_spin_unlock(&timebase_lock);
+}
index 1d15424..e1e3059 100644 (file)
@@ -119,6 +119,8 @@ notrace unsigned long __init early_init(unsigned long dt_ptr)
  */
 notrace void __init machine_init(unsigned long dt_ptr)
 {
+       lockdep_init();
+
        /* Enable early debugging if any specified (see udbg.h) */
        udbg_early_init();
 
index 65484b2..0b47de0 100644 (file)
@@ -68,7 +68,8 @@ EXPORT_PER_CPU_SYMBOL(cpu_core_map);
 /* SMP operations for this machine */
 struct smp_ops_t *smp_ops;
 
-static volatile unsigned int cpu_callin_map[NR_CPUS];
+/* Can't be static due to PowerMac hackery */
+volatile unsigned int cpu_callin_map[NR_CPUS];
 
 int smt_enabled_at_boot = 1;
 
index 0362a89..acb74a1 100644 (file)
@@ -219,7 +219,7 @@ void udbg_init_pas_realmode(void)
 #ifdef CONFIG_PPC_EARLY_DEBUG_44x
 #include <platforms/44x/44x.h>
 
-static int udbg_44x_as1_flush(void)
+static void udbg_44x_as1_flush(void)
 {
        if (udbg_comport) {
                while ((as1_readb(&udbg_comport->lsr) & LSR_THRE) == 0)
index 2d2192e..3e68363 100644 (file)
@@ -30,3 +30,4 @@ obj-$(CONFIG_PPC_MM_SLICES)   += slice.o
 obj-$(CONFIG_HUGETLB_PAGE)     += hugetlbpage.o
 obj-$(CONFIG_PPC_SUBPAGE_PROT) += subpage-prot.o
 obj-$(CONFIG_NOT_COHERENT_CACHE) += dma-noncoherent.o
+obj-$(CONFIG_HIGHMEM)          += highmem.o
diff --git a/arch/powerpc/mm/highmem.c b/arch/powerpc/mm/highmem.c
new file mode 100644 (file)
index 0000000..c2186c7
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * highmem.c: virtual kernel memory mappings for high memory
+ *
+ * PowerPC version, stolen from the i386 version.
+ *
+ * Used in CONFIG_HIGHMEM systems for memory pages which
+ * are not addressable by direct kernel virtual addresses.
+ *
+ * Copyright (C) 1999 Gerhard Wichert, Siemens AG
+ *                   Gerhard.Wichert@pdb.siemens.de
+ *
+ *
+ * Redesigned the x86 32-bit VM architecture to deal with
+ * up to 16 Terrabyte physical memory. With current x86 CPUs
+ * we now support up to 64 Gigabytes physical RAM.
+ *
+ * Copyright (C) 1999 Ingo Molnar <mingo@redhat.com>
+ *
+ * Reworked for PowerPC by various contributors. Moved from
+ * highmem.h by Benjamin Herrenschmidt (c) 2009 IBM Corp.
+ */
+
+#include <linux/highmem.h>
+#include <linux/module.h>
+
+/*
+ * The use of kmap_atomic/kunmap_atomic is discouraged - kmap/kunmap
+ * gives a more generic (and caching) interface. But kmap_atomic can
+ * be used in IRQ contexts, so in some (very limited) cases we need
+ * it.
+ */
+void *kmap_atomic_prot(struct page *page, enum km_type type, pgprot_t prot)
+{
+       unsigned int idx;
+       unsigned long vaddr;
+
+       /* even !CONFIG_PREEMPT needs this, for in_atomic in do_page_fault */
+       pagefault_disable();
+       if (!PageHighMem(page))
+               return page_address(page);
+
+       debug_kmap_atomic(type);
+       idx = type + KM_TYPE_NR*smp_processor_id();
+       vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
+#ifdef CONFIG_DEBUG_HIGHMEM
+       BUG_ON(!pte_none(*(kmap_pte-idx)));
+#endif
+       __set_pte_at(&init_mm, vaddr, kmap_pte-idx, mk_pte(page, prot), 1);
+       local_flush_tlb_page(NULL, vaddr);
+
+       return (void*) vaddr;
+}
+EXPORT_SYMBOL(kmap_atomic_prot);
+
+void kunmap_atomic(void *kvaddr, enum km_type type)
+{
+#ifdef CONFIG_DEBUG_HIGHMEM
+       unsigned long vaddr = (unsigned long) kvaddr & PAGE_MASK;
+       enum fixed_addresses idx = type + KM_TYPE_NR*smp_processor_id();
+
+       if (vaddr < __fix_to_virt(FIX_KMAP_END)) {
+               pagefault_enable();
+               return;
+       }
+
+       BUG_ON(vaddr != __fix_to_virt(FIX_KMAP_BEGIN + idx));
+
+       /*
+        * force other mappings to Oops if they'll try to access
+        * this pte without first remap it
+        */
+       pte_clear(&init_mm, vaddr, kmap_pte-idx);
+       local_flush_tlb_page(NULL, vaddr);
+#endif
+       pagefault_enable();
+}
+EXPORT_SYMBOL(kunmap_atomic);
index 42e09a9..0362c88 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/interrupt.h>
 #include <linux/delay.h>
 #include <linux/of_gpio.h>
+#include <linux/of_i2c.h>
 
 #include <asm/machdep.h>
 #include <asm/prom.h>
@@ -65,7 +66,6 @@ define_machine(warp) {
 
 static u32 post_info;
 
-/* I am not sure this is the best place for this... */
 static int __init warp_post_info(void)
 {
        struct device_node *np;
@@ -194,9 +194,9 @@ static int pika_setup_leds(void)
        return 0;
 }
 
-static void pika_setup_critical_temp(struct i2c_client *client)
+static void pika_setup_critical_temp(struct device_node *np,
+                                    struct i2c_client *client)
 {
-       struct device_node *np;
        int irq, rc;
 
        /* Do this before enabling critical temp interrupt since we
@@ -208,14 +208,7 @@ static void pika_setup_critical_temp(struct i2c_client *client)
        i2c_smbus_write_byte_data(client, 2, 65); /* Thigh */
        i2c_smbus_write_byte_data(client, 3,  0); /* Tlow */
 
-       np = of_find_compatible_node(NULL, NULL, "adi,ad7414");
-       if (np == NULL) {
-               printk(KERN_ERR __FILE__ ": Unable to find ad7414\n");
-               return;
-       }
-
        irq = irq_of_parse_and_map(np, 0);
-       of_node_put(np);
        if (irq  == NO_IRQ) {
                printk(KERN_ERR __FILE__ ": Unable to get ad7414 irq\n");
                return;
@@ -244,32 +237,24 @@ static inline void pika_dtm_check_fan(void __iomem *fpga)
 
 static int pika_dtm_thread(void __iomem *fpga)
 {
-       struct i2c_adapter *adap;
+       struct device_node *np;
        struct i2c_client *client;
 
-       /* We loop in case either driver was compiled as a module and
-        * has not been insmoded yet.
-        */
-       while (!(adap = i2c_get_adapter(0))) {
-               set_current_state(TASK_INTERRUPTIBLE);
-               schedule_timeout(HZ);
-       }
-
-       while (1) {
-               list_for_each_entry(client, &adap->clients, list)
-                       if (client->addr == 0x4a)
-                               goto found_it;
+       np = of_find_compatible_node(NULL, NULL, "adi,ad7414");
+       if (np == NULL)
+               return -ENOENT;
 
-               set_current_state(TASK_INTERRUPTIBLE);
-               schedule_timeout(HZ);
+       client = of_find_i2c_device_by_node(np);
+       if (client == NULL) {
+               of_node_put(np);
+               return -ENOENT;
        }
 
-found_it:
-       pika_setup_critical_temp(client);
+       pika_setup_critical_temp(np, client);
 
-       i2c_put_adapter(adap);
+       of_node_put(np);
 
-       printk(KERN_INFO "PIKA DTM thread running.\n");
+       printk(KERN_INFO "Warp DTM thread running.\n");
 
        while (!kthread_should_stop()) {
                int val;
@@ -291,7 +276,6 @@ found_it:
        return 0;
 }
 
-
 static int __init pika_dtm_start(void)
 {
        struct task_struct *dtm_thread;
index 77f90b3..60ed9c0 100644 (file)
@@ -285,6 +285,7 @@ static struct of_device_id mpc85xx_ids[] = {
        { .type = "qe", },
        { .compatible = "fsl,qe", },
        { .compatible = "gianfar", },
+       { .compatible = "fsl,rapidio-delta", },
        {},
 };
 
index cc0b0db..62c592e 100644 (file)
@@ -52,20 +52,19 @@ smp_85xx_kick_cpu(int nr)
 
        pr_debug("smp_85xx_kick_cpu: kick CPU #%d\n", nr);
 
-       local_irq_save(flags);
-
        np = of_get_cpu_node(nr, NULL);
        cpu_rel_addr = of_get_property(np, "cpu-release-addr", NULL);
 
        if (cpu_rel_addr == NULL) {
                printk(KERN_ERR "No cpu-release-addr for cpu %d\n", nr);
-               local_irq_restore(flags);
                return;
        }
 
        /* Map the spin table */
        bptr_vaddr = ioremap(*cpu_rel_addr, SIZE_BOOT_ENTRY);
 
+       local_irq_save(flags);
+
        out_be32(bptr_vaddr + BOOT_ENTRY_PIR, nr);
        out_be32(bptr_vaddr + BOOT_ENTRY_ADDR_LOWER, __pa(__early_start));
 
@@ -73,10 +72,10 @@ smp_85xx_kick_cpu(int nr)
        while ((__secondary_hold_acknowledge != nr) && (++n < 1000))
                mdelay(1);
 
-       iounmap(bptr_vaddr);
-
        local_irq_restore(flags);
 
+       iounmap(bptr_vaddr);
+
        pr_debug("waited %d msecs for CPU #%d.\n", n, nr);
 }
 
index d0e8443..747d8fb 100644 (file)
@@ -102,10 +102,11 @@ static struct of_device_id __initdata socrates_of_bus_ids[] = {
        {},
 };
 
-static void __init socrates_init(void)
+static int __init socrates_publish_devices(void)
 {
-       of_platform_bus_probe(NULL, socrates_of_bus_ids, NULL);
+       return of_platform_bus_probe(NULL, socrates_of_bus_ids, NULL);
 }
+machine_device_initcall(socrates, socrates_publish_devices);
 
 /*
  * Called very early, device-tree isn't unflattened
@@ -124,7 +125,6 @@ define_machine(socrates) {
        .name                   = "Socrates",
        .probe                  = socrates_probe,
        .setup_arch             = socrates_setup_arch,
-       .init                   = socrates_init,
        .init_IRQ               = socrates_pic_init,
        .get_irq                = mpic_get_irq,
        .restart                = fsl_rstcr_restart,
index ee01532..1b42605 100644 (file)
@@ -32,7 +32,6 @@
 
 #include <sysdev/fsl_soc.h>
 #include <sysdev/fsl_pci.h>
-#include <linux/of_platform.h>
 
 /* A few bit definitions needed for fixups on some boards */
 #define MPC85xx_L2CTL_L2E              0x80000000 /* L2 enable */
index 9046803..bc97fad 100644 (file)
@@ -36,7 +36,6 @@
 #include <asm/prom.h>
 #include <asm/smp.h>
 #include <asm/paca.h>
-#include <asm/time.h>
 #include <asm/machdep.h>
 #include <asm/cputable.h>
 #include <asm/firmware.h>
@@ -140,31 +139,6 @@ static void __devinit smp_cell_setup_cpu(int cpu)
        mtspr(SPRN_DABRX, DABRX_KERNEL | DABRX_USER);
 }
 
-static DEFINE_SPINLOCK(timebase_lock);
-static unsigned long timebase = 0;
-
-static void __devinit cell_give_timebase(void)
-{
-       spin_lock(&timebase_lock);
-       rtas_call(rtas_token("freeze-time-base"), 0, 1, NULL);
-       timebase = get_tb();
-       spin_unlock(&timebase_lock);
-
-       while (timebase)
-               barrier();
-       rtas_call(rtas_token("thaw-time-base"), 0, 1, NULL);
-}
-
-static void __devinit cell_take_timebase(void)
-{
-       while (!timebase)
-               barrier();
-       spin_lock(&timebase_lock);
-       set_tb(timebase >> 32, timebase & 0xffffffff);
-       timebase = 0;
-       spin_unlock(&timebase_lock);
-}
-
 static void __devinit smp_cell_kick_cpu(int nr)
 {
        BUG_ON(nr < 0 || nr >= NR_CPUS);
@@ -224,8 +198,8 @@ void __init smp_init_cell(void)
 
        /* Non-lpar has additional take/give timebase */
        if (rtas_token("freeze-time-base") != RTAS_UNKNOWN_SERVICE) {
-               smp_ops->give_timebase = cell_give_timebase;
-               smp_ops->take_timebase = cell_take_timebase;
+               smp_ops->give_timebase = rtas_give_timebase;
+               smp_ops->take_timebase = rtas_take_timebase;
        }
 
        DBG(" <- smp_init_cell()\n");
index 10a4a4d..02cafec 100644 (file)
@@ -26,7 +26,6 @@
 #include <asm/io.h>
 #include <asm/prom.h>
 #include <asm/smp.h>
-#include <asm/time.h>
 #include <asm/machdep.h>
 #include <asm/mpic.h>
 #include <asm/rtas.h>
@@ -42,40 +41,12 @@ static void __devinit smp_chrp_setup_cpu(int cpu_nr)
        mpic_setup_this_cpu();
 }
 
-static DEFINE_SPINLOCK(timebase_lock);
-static unsigned int timebase_upper = 0, timebase_lower = 0;
-
-void __devinit smp_chrp_give_timebase(void)
-{
-       spin_lock(&timebase_lock);
-       rtas_call(rtas_token("freeze-time-base"), 0, 1, NULL);
-       timebase_upper = get_tbu();
-       timebase_lower = get_tbl();
-       spin_unlock(&timebase_lock);
-
-       while (timebase_upper || timebase_lower)
-               barrier();
-       rtas_call(rtas_token("thaw-time-base"), 0, 1, NULL);
-}
-
-void __devinit smp_chrp_take_timebase(void)
-{
-       while (!(timebase_upper || timebase_lower))
-               barrier();
-       spin_lock(&timebase_lock);
-       set_tb(timebase_upper, timebase_lower);
-       timebase_upper = 0;
-       timebase_lower = 0;
-       spin_unlock(&timebase_lock);
-       printk("CPU %i taken timebase\n", smp_processor_id());
-}
-
 /* CHRP with openpic */
 struct smp_ops_t chrp_smp_ops = {
        .message_pass = smp_mpic_message_pass,
        .probe = smp_mpic_probe,
        .kick_cpu = smp_chrp_kick_cpu,
        .setup_cpu = smp_chrp_setup_cpu,
-       .give_timebase = smp_chrp_give_timebase,
-       .take_timebase = smp_chrp_take_timebase,
+       .give_timebase = rtas_give_timebase,
+       .take_timebase = rtas_take_timebase,
 };
index 153051e..a461934 100644 (file)
@@ -71,20 +71,25 @@ static void pas_restart(char *cmd)
 }
 
 #ifdef CONFIG_SMP
-static DEFINE_SPINLOCK(timebase_lock);
+static raw_spinlock_t timebase_lock;
 static unsigned long timebase;
 
 static void __devinit pas_give_timebase(void)
 {
-       spin_lock(&timebase_lock);
+       unsigned long flags;
+
+       local_irq_save(flags);
+       hard_irq_disable();
+       __raw_spin_lock(&timebase_lock);
        mtspr(SPRN_TBCTL, TBCTL_FREEZE);
        isync();
        timebase = get_tb();
-       spin_unlock(&timebase_lock);
+       __raw_spin_unlock(&timebase_lock);
 
        while (timebase)
                barrier();
        mtspr(SPRN_TBCTL, TBCTL_RESTART);
+       local_irq_restore(flags);
 }
 
 static void __devinit pas_take_timebase(void)
@@ -92,10 +97,10 @@ static void __devinit pas_take_timebase(void)
        while (!timebase)
                smp_rmb();
 
-       spin_lock(&timebase_lock);
+       __raw_spin_lock(&timebase_lock);
        set_tb(timebase >> 32, timebase & 0xffffffff);
        timebase = 0;
-       spin_unlock(&timebase_lock);
+       __raw_spin_unlock(&timebase_lock);
 }
 
 struct smp_ops_t pas_smp_ops = {
index 86f69a4..c205226 100644 (file)
@@ -103,11 +103,6 @@ unsigned long smu_cmdbuf_abs;
 EXPORT_SYMBOL(smu_cmdbuf_abs);
 #endif
 
-#ifdef CONFIG_SMP
-extern struct smp_ops_t psurge_smp_ops;
-extern struct smp_ops_t core99_smp_ops;
-#endif /* CONFIG_SMP */
-
 static void pmac_show_cpuinfo(struct seq_file *m)
 {
        struct device_node *np;
@@ -341,34 +336,6 @@ static void __init pmac_setup_arch(void)
                ROOT_DEV = DEFAULT_ROOT_DEVICE;
 #endif
 
-#ifdef CONFIG_SMP
-       /* Check for Core99 */
-       ic = of_find_node_by_name(NULL, "uni-n");
-       if (!ic)
-               ic = of_find_node_by_name(NULL, "u3");
-       if (!ic)
-               ic = of_find_node_by_name(NULL, "u4");
-       if (ic) {
-               of_node_put(ic);
-               smp_ops = &core99_smp_ops;
-       }
-#ifdef CONFIG_PPC32
-       else {
-               /*
-                * We have to set bits in cpu_possible_map here since the
-                * secondary CPU(s) aren't in the device tree, and
-                * setup_per_cpu_areas only allocates per-cpu data for
-                * CPUs in the cpu_possible_map.
-                */
-               int cpu;
-
-               for (cpu = 1; cpu < 4 && cpu < NR_CPUS; ++cpu)
-                       cpu_set(cpu, cpu_possible_map);
-               smp_ops = &psurge_smp_ops;
-       }
-#endif
-#endif /* CONFIG_SMP */
-
 #ifdef CONFIG_ADB
        if (strstr(cmd_line, "adb_sync")) {
                extern int __adb_probe_sync;
@@ -512,6 +479,14 @@ static void __init pmac_init_early(void)
 #ifdef CONFIG_PPC64
        iommu_init_early_dart();
 #endif
+
+       /* SMP Init has to be done early as we need to patch up
+        * cpu_possible_map before interrupt stacks are allocated
+        * or kaboom...
+        */
+#ifdef CONFIG_SMP
+       pmac_setup_smp();
+#endif
 }
 
 static int __init pmac_declare_of_platform_devices(void)
index cf1dbe7..6d4da7b 100644 (file)
 extern void __secondary_start_pmac_0(void);
 extern int pmac_pfunc_base_install(void);
 
-#ifdef CONFIG_PPC32
+static void (*pmac_tb_freeze)(int freeze);
+static u64 timebase;
+static int tb_req;
 
-/* Sync flag for HW tb sync */
-static volatile int sec_tb_reset = 0;
+#ifdef CONFIG_PPC32
 
 /*
  * Powersurge (old powermac SMP) support.
@@ -294,6 +295,9 @@ static int __init smp_psurge_probe(void)
                psurge_quad_init();
                /* All released cards using this HW design have 4 CPUs */
                ncpus = 4;
+               /* No sure how timebase sync works on those, let's use SW */
+               smp_ops->give_timebase = smp_generic_give_timebase;
+               smp_ops->take_timebase = smp_generic_take_timebase;
        } else {
                iounmap(quad_base);
                if ((in_8(hhead_base + HHEAD_CONFIG) & 0x02) == 0) {
@@ -308,18 +312,15 @@ static int __init smp_psurge_probe(void)
        psurge_start = ioremap(PSURGE_START, 4);
        psurge_pri_intr = ioremap(PSURGE_PRI_INTR, 4);
 
-       /*
-        * This is necessary because OF doesn't know about the
+       /* This is necessary because OF doesn't know about the
         * secondary cpu(s), and thus there aren't nodes in the
         * device tree for them, and smp_setup_cpu_maps hasn't
-        * set their bits in cpu_possible_map and cpu_present_map.
+        * set their bits in cpu_present_map.
         */
        if (ncpus > NR_CPUS)
                ncpus = NR_CPUS;
-       for (i = 1; i < ncpus ; ++i) {
+       for (i = 1; i < ncpus ; ++i)
                cpu_set(i, cpu_present_map);
-               set_hard_smp_processor_id(i, i);
-       }
 
        if (ppc_md.progress) ppc_md.progress("smp_psurge_probe - done", 0x352);
 
@@ -329,8 +330,14 @@ static int __init smp_psurge_probe(void)
 static void __init smp_psurge_kick_cpu(int nr)
 {
        unsigned long start = __pa(__secondary_start_pmac_0) + nr * 8;
-       unsigned long a;
-       int i;
+       unsigned long a, flags;
+       int i, j;
+
+       /* Defining this here is evil ... but I prefer hiding that
+        * crap to avoid giving people ideas that they can do the
+        * same.
+        */
+       extern volatile unsigned int cpu_callin_map[NR_CPUS];
 
        /* may need to flush here if secondary bats aren't setup */
        for (a = KERNELBASE; a < KERNELBASE + 0x800000; a += 32)
@@ -339,47 +346,52 @@ static void __init smp_psurge_kick_cpu(int nr)
 
        if (ppc_md.progress) ppc_md.progress("smp_psurge_kick_cpu", 0x353);
 
+       /* This is going to freeze the timeebase, we disable interrupts */
+       local_irq_save(flags);
+
        out_be32(psurge_start, start);
        mb();
 
        psurge_set_ipi(nr);
+
        /*
         * We can't use udelay here because the timebase is now frozen.
         */
        for (i = 0; i < 2000; ++i)
-               barrier();
+               asm volatile("nop" : : : "memory");
        psurge_clr_ipi(nr);
 
-       if (ppc_md.progress) ppc_md.progress("smp_psurge_kick_cpu - done", 0x354);
-}
-
-/*
- * With the dual-cpu powersurge board, the decrementers and timebases
- * of both cpus are frozen after the secondary cpu is started up,
- * until we give the secondary cpu another interrupt.  This routine
- * uses this to get the timebases synchronized.
- *  -- paulus.
- */
-static void __init psurge_dual_sync_tb(int cpu_nr)
-{
-       int t;
-
-       set_dec(tb_ticks_per_jiffy);
-       /* XXX fixme */
-       set_tb(0, 0);
-
-       if (cpu_nr > 0) {
+       /*
+        * Also, because the timebase is frozen, we must not return to the
+        * caller which will try to do udelay's etc... Instead, we wait -here-
+        * for the CPU to callin.
+        */
+       for (i = 0; i < 100000 && !cpu_callin_map[nr]; ++i) {
+               for (j = 1; j < 10000; j++)
+                       asm volatile("nop" : : : "memory");
+               asm volatile("sync" : : : "memory");
+       }
+       if (!cpu_callin_map[nr])
+               goto stuck;
+
+       /* And we do the TB sync here too for standard dual CPU cards */
+       if (psurge_type == PSURGE_DUAL) {
+               while(!tb_req)
+                       barrier();
+               tb_req = 0;
+               mb();
+               timebase = get_tb();
+               mb();
+               while (timebase)
+                       barrier();
                mb();
-               sec_tb_reset = 1;
-               return;
        }
+ stuck:
+       /* now interrupt the secondary, restarting both TBs */
+       if (psurge_type == PSURGE_DUAL)
+               psurge_set_ipi(1);
 
-       /* wait for the secondary to have reset its TB before proceeding */
-       for (t = 10000000; t > 0 && !sec_tb_reset; --t)
-               ;
-
-       /* now interrupt the secondary, starting both TBs */
-       psurge_set_ipi(1);
+       if (ppc_md.progress) ppc_md.progress("smp_psurge_kick_cpu - done", 0x354);
 }
 
 static struct irqaction psurge_irqaction = {
@@ -390,36 +402,35 @@ static struct irqaction psurge_irqaction = {
 
 static void __init smp_psurge_setup_cpu(int cpu_nr)
 {
+       if (cpu_nr != 0)
+               return;
 
-       if (cpu_nr == 0) {
-               /* If we failed to start the second CPU, we should still
-                * send it an IPI to start the timebase & DEC or we might
-                * have them stuck.
-                */
-               if (num_online_cpus() < 2) {
-                       if (psurge_type == PSURGE_DUAL)
-                               psurge_set_ipi(1);
-                       return;
-               }
-               /* reset the entry point so if we get another intr we won't
-                * try to startup again */
-               out_be32(psurge_start, 0x100);
-               if (setup_irq(30, &psurge_irqaction))
-                       printk(KERN_ERR "Couldn't get primary IPI interrupt");
-       }
-
-       if (psurge_type == PSURGE_DUAL)
-               psurge_dual_sync_tb(cpu_nr);
+       /* reset the entry point so if we get another intr we won't
+        * try to startup again */
+       out_be32(psurge_start, 0x100);
+       if (setup_irq(30, &psurge_irqaction))
+               printk(KERN_ERR "Couldn't get primary IPI interrupt");
 }
 
 void __init smp_psurge_take_timebase(void)
 {
-       /* Dummy implementation */
+       if (psurge_type != PSURGE_DUAL)
+               return;
+
+       tb_req = 1;
+       mb();
+       while (!timebase)
+               barrier();
+       mb();
+       set_tb(timebase >> 32, timebase & 0xffffffff);
+       timebase = 0;
+       mb();
+       set_dec(tb_ticks_per_jiffy/2);
 }
 
 void __init smp_psurge_give_timebase(void)
 {
-       /* Dummy implementation */
+       /* Nothing to do here */
 }
 
 /* PowerSurge-style Macs */
@@ -437,9 +448,6 @@ struct smp_ops_t psurge_smp_ops = {
  * Core 99 and later support
  */
 
-static void (*pmac_tb_freeze)(int freeze);
-static u64 timebase;
-static int tb_req;
 
 static void smp_core99_give_timebase(void)
 {
@@ -478,7 +486,6 @@ static void __devinit smp_core99_take_timebase(void)
        set_tb(timebase >> 32, timebase & 0xffffffff);
        timebase = 0;
        mb();
-       set_dec(tb_ticks_per_jiffy/2);
 
        local_irq_restore(flags);
 }
@@ -920,3 +927,34 @@ struct smp_ops_t core99_smp_ops = {
 # endif
 #endif
 };
+
+void __init pmac_setup_smp(void)
+{
+       struct device_node *np;
+
+       /* Check for Core99 */
+       np = of_find_node_by_name(NULL, "uni-n");
+       if (!np)
+               np = of_find_node_by_name(NULL, "u3");
+       if (!np)
+               np = of_find_node_by_name(NULL, "u4");
+       if (np) {
+               of_node_put(np);
+               smp_ops = &core99_smp_ops;
+       }
+#ifdef CONFIG_PPC32
+       else {
+               /* We have to set bits in cpu_possible_map here since the
+                * secondary CPU(s) aren't in the device tree. Various
+                * things won't be initialized for CPUs not in the possible
+                * map, so we really need to fix it up here.
+                */
+               int cpu;
+
+               for (cpu = 1; cpu < 4 && cpu < NR_CPUS; ++cpu)
+                       cpu_set(cpu, cpu_possible_map);
+               smp_ops = &psurge_smp_ops;
+       }
+#endif /* CONFIG_PPC32 */
+}
+
index 1a231c3..1f8f6cf 100644 (file)
@@ -35,7 +35,6 @@
 #include <asm/prom.h>
 #include <asm/smp.h>
 #include <asm/paca.h>
-#include <asm/time.h>
 #include <asm/machdep.h>
 #include <asm/cputable.h>
 #include <asm/firmware.h>
@@ -118,31 +117,6 @@ static void __devinit smp_xics_setup_cpu(int cpu)
 }
 #endif /* CONFIG_XICS */
 
-static DEFINE_SPINLOCK(timebase_lock);
-static unsigned long timebase = 0;
-
-static void __devinit pSeries_give_timebase(void)
-{
-       spin_lock(&timebase_lock);
-       rtas_call(rtas_token("freeze-time-base"), 0, 1, NULL);
-       timebase = get_tb();
-       spin_unlock(&timebase_lock);
-
-       while (timebase)
-               barrier();
-       rtas_call(rtas_token("thaw-time-base"), 0, 1, NULL);
-}
-
-static void __devinit pSeries_take_timebase(void)
-{
-       while (!timebase)
-               barrier();
-       spin_lock(&timebase_lock);
-       set_tb(timebase >> 32, timebase & 0xffffffff);
-       timebase = 0;
-       spin_unlock(&timebase_lock);
-}
-
 static void __devinit smp_pSeries_kick_cpu(int nr)
 {
        BUG_ON(nr < 0 || nr >= NR_CPUS);
@@ -209,8 +183,8 @@ static void __init smp_init_pseries(void)
 
        /* Non-lpar has additional take/give timebase */
        if (rtas_token("freeze-time-base") != RTAS_UNKNOWN_SERVICE) {
-               smp_ops->give_timebase = pSeries_give_timebase;
-               smp_ops->take_timebase = pSeries_take_timebase;
+               smp_ops->give_timebase = rtas_give_timebase;
+               smp_ops->take_timebase = rtas_take_timebase;
        }
 
        pr_debug(" <- smp_init_pSeries()\n");
index 9c3af50..d46de1f 100644 (file)
@@ -279,28 +279,29 @@ static void _mpic_map_mmio(struct mpic *mpic, phys_addr_t phys_addr,
 }
 
 #ifdef CONFIG_PPC_DCR
-static void _mpic_map_dcr(struct mpic *mpic, struct mpic_reg_bank *rb,
+static void _mpic_map_dcr(struct mpic *mpic, struct device_node *node,
+                         struct mpic_reg_bank *rb,
                          unsigned int offset, unsigned int size)
 {
        const u32 *dbasep;
 
-       dbasep = of_get_property(mpic->irqhost->of_node, "dcr-reg", NULL);
+       dbasep = of_get_property(node, "dcr-reg", NULL);
 
-       rb->dhost = dcr_map(mpic->irqhost->of_node, *dbasep + offset, size);
+       rb->dhost = dcr_map(node, *dbasep + offset, size);
        BUG_ON(!DCR_MAP_OK(rb->dhost));
 }
 
-static inline void mpic_map(struct mpic *mpic, phys_addr_t phys_addr,
-                           struct mpic_reg_bank *rb, unsigned int offset,
-                           unsigned int size)
+static inline void mpic_map(struct mpic *mpic, struct device_node *node,
+                           phys_addr_t phys_addr, struct mpic_reg_bank *rb,
+                           unsigned int offset, unsigned int size)
 {
        if (mpic->flags & MPIC_USES_DCR)
-               _mpic_map_dcr(mpic, rb, offset, size);
+               _mpic_map_dcr(mpic, node, rb, offset, size);
        else
                _mpic_map_mmio(mpic, phys_addr, rb, offset, size);
 }
 #else /* CONFIG_PPC_DCR */
-#define mpic_map(m,p,b,o,s)    _mpic_map_mmio(m,p,b,o,s)
+#define mpic_map(m,n,p,b,o,s)  _mpic_map_mmio(m,p,b,o,s)
 #endif /* !CONFIG_PPC_DCR */
 
 
@@ -1052,11 +1053,10 @@ struct mpic * __init mpic_alloc(struct device_node *node,
        int             intvec_top;
        u64             paddr = phys_addr;
 
-       mpic = alloc_bootmem(sizeof(struct mpic));
+       mpic = kzalloc(sizeof(struct mpic), GFP_KERNEL);
        if (mpic == NULL)
                return NULL;
-       
-       memset(mpic, 0, sizeof(struct mpic));
+
        mpic->name = name;
 
        mpic->hc_irq = mpic_irq_chip;
@@ -1152,8 +1152,8 @@ struct mpic * __init mpic_alloc(struct device_node *node,
        }
 
        /* Map the global registers */
-       mpic_map(mpic, paddr, &mpic->gregs, MPIC_INFO(GREG_BASE), 0x1000);
-       mpic_map(mpic, paddr, &mpic->tmregs, MPIC_INFO(TIMER_BASE), 0x1000);
+       mpic_map(mpic, node, paddr, &mpic->gregs, MPIC_INFO(GREG_BASE), 0x1000);
+       mpic_map(mpic, node, paddr, &mpic->tmregs, MPIC_INFO(TIMER_BASE), 0x1000);
 
        /* Reset */
        if (flags & MPIC_WANTS_RESET) {
@@ -1194,7 +1194,7 @@ struct mpic * __init mpic_alloc(struct device_node *node,
 
        /* Map the per-CPU registers */
        for (i = 0; i < mpic->num_cpus; i++) {
-               mpic_map(mpic, paddr, &mpic->cpuregs[i],
+               mpic_map(mpic, node, paddr, &mpic->cpuregs[i],
                         MPIC_INFO(CPU_BASE) + i * MPIC_INFO(CPU_STRIDE),
                         0x1000);
        }
@@ -1202,7 +1202,7 @@ struct mpic * __init mpic_alloc(struct device_node *node,
        /* Initialize main ISU if none provided */
        if (mpic->isu_size == 0) {
                mpic->isu_size = mpic->num_sources;
-               mpic_map(mpic, paddr, &mpic->isus[0],
+               mpic_map(mpic, node, paddr, &mpic->isus[0],
                         MPIC_INFO(IRQ_BASE), MPIC_INFO(IRQ_STRIDE) * mpic->isu_size);
        }
        mpic->isu_shift = 1 + __ilog2(mpic->isu_size - 1);
@@ -1256,8 +1256,10 @@ void __init mpic_assign_isu(struct mpic *mpic, unsigned int isu_num,
 
        BUG_ON(isu_num >= MPIC_MAX_ISU);
 
-       mpic_map(mpic, paddr, &mpic->isus[isu_num], 0,
+       mpic_map(mpic, mpic->irqhost->of_node,
+                paddr, &mpic->isus[isu_num], 0,
                 MPIC_INFO(IRQ_STRIDE) * mpic->isu_size);
+
        if ((isu_first + mpic->isu_size) > mpic->num_sources)
                mpic->num_sources = isu_first + mpic->isu_size;
 }
index b28b0e5..237e365 100644 (file)
@@ -112,6 +112,7 @@ int qe_issue_cmd(u32 cmd, u32 device, u8 mcn_protocol, u32 cmd_input)
 {
        unsigned long flags;
        u8 mcn_shift = 0, dev_shift = 0;
+       u32 ret;
 
        spin_lock_irqsave(&qe_lock, flags);
        if (cmd == QE_RESET) {
@@ -139,11 +140,13 @@ int qe_issue_cmd(u32 cmd, u32 device, u8 mcn_protocol, u32 cmd_input)
        }
 
        /* wait for the QE_CR_FLG to clear */
-       while(in_be32(&qe_immr->cp.cecr) & QE_CR_FLG)
-               cpu_relax();
+       ret = spin_event_timeout((in_be32(&qe_immr->cp.cecr) & QE_CR_FLG) == 0,
+                          100, 0);
+       /* On timeout (e.g. failure), the expression will be false (ret == 0),
+          otherwise it will be true (ret == 1). */
        spin_unlock_irqrestore(&qe_lock, flags);
 
-       return 0;
+       return ret == 1;
 }
 EXPORT_SYMBOL(qe_issue_cmd);
 
index a27d0d5..1cd02f6 100644 (file)
@@ -99,7 +99,9 @@ struct kvm_s390_sie_block {
        __u8    reservedd0[48];         /* 0x00d0 */
        __u64   gcr[16];                /* 0x0100 */
        __u64   gbea;                   /* 0x0180 */
-       __u8    reserved188[120];       /* 0x0188 */
+       __u8    reserved188[24];        /* 0x0188 */
+       __u32   fac;                    /* 0x01a0 */
+       __u8    reserved1a4[92];        /* 0x01a4 */
 } __attribute__((packed));
 
 struct kvm_vcpu_stat {
index c18b21d..90d9d1b 100644 (file)
@@ -25,6 +25,7 @@
 #include <asm/lowcore.h>
 #include <asm/pgtable.h>
 #include <asm/nmi.h>
+#include <asm/system.h>
 #include "kvm-s390.h"
 #include "gaccess.h"
 
@@ -69,6 +70,7 @@ struct kvm_stats_debugfs_item debugfs_entries[] = {
        { NULL }
 };
 
+static unsigned long long *facilities;
 
 /* Section: not file related */
 void kvm_arch_hardware_enable(void *garbage)
@@ -288,6 +290,7 @@ int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
        vcpu->arch.sie_block->gmsor = vcpu->kvm->arch.guest_origin;
        vcpu->arch.sie_block->ecb   = 2;
        vcpu->arch.sie_block->eca   = 0xC1002001U;
+       vcpu->arch.sie_block->fac   = (int) (long) facilities;
        hrtimer_init(&vcpu->arch.ckc_timer, CLOCK_REALTIME, HRTIMER_MODE_ABS);
        tasklet_init(&vcpu->arch.tasklet, kvm_s390_tasklet,
                     (unsigned long) vcpu);
@@ -739,11 +742,29 @@ gfn_t unalias_gfn(struct kvm *kvm, gfn_t gfn)
 
 static int __init kvm_s390_init(void)
 {
-       return kvm_init(NULL, sizeof(struct kvm_vcpu), THIS_MODULE);
+       int ret;
+       ret = kvm_init(NULL, sizeof(struct kvm_vcpu), THIS_MODULE);
+       if (ret)
+               return ret;
+
+       /*
+        * guests can ask for up to 255+1 double words, we need a full page
+        * to hold the maximum amount of facilites. On the other hand, we
+        * only set facilities that are known to work in KVM.
+        */
+       facilities = (unsigned long long *) get_zeroed_page(GFP_DMA);
+       if (!facilities) {
+               kvm_exit();
+               return -ENOMEM;
+       }
+       stfle(facilities, 1);
+       facilities[0] &= 0xff00fff3f0700000ULL;
+       return 0;
 }
 
 static void __exit kvm_s390_exit(void)
 {
+       free_page((unsigned long) facilities);
        kvm_exit();
 }
 
index 93ecd06..d426aac 100644 (file)
@@ -158,7 +158,7 @@ static int handle_stfl(struct kvm_vcpu *vcpu)
 
        vcpu->stat.instruction_stfl++;
        /* only pass the facility bits, which we can handle */
-       facility_list &= 0xfe00fff3;
+       facility_list &= 0xff00fff3;
 
        rc = copy_to_guest(vcpu, offsetof(struct _lowcore, stfl_fac_list),
                           &facility_list, sizeof(facility_list));
index 8ece0b5..39224b5 100644 (file)
@@ -61,10 +61,6 @@ config EARLY_PRINTK
          select both the EARLY_SCIF_CONSOLE and SH_STANDARD_BIOS, using
          the kernel command line option to toggle back and forth.
 
-config DEBUG_BOOTMEM
-       depends on DEBUG_KERNEL
-       bool "Debug BOOTMEM initialization"
-
 config DEBUG_STACKOVERFLOW
        bool "Check for stack overflows"
        depends on DEBUG_KERNEL && SUPERH32
index 9c3a332..1804556 100644 (file)
@@ -50,7 +50,7 @@ unsigned char se7206_inb_p(unsigned long port)
 
 unsigned short se7206_inw(unsigned long port)
 {
-       return *port2adr(port);;
+       return *port2adr(port);
 }
 
 void se7206_outb(unsigned char value, unsigned long port)
index 9cd04bd..c050a8d 100644 (file)
@@ -23,6 +23,8 @@
 #include <media/sh_mobile_ceu.h>
 #include <asm/io.h>
 #include <asm/heartbeat.h>
+#include <asm/sh_eth.h>
+#include <asm/clock.h>
 #include <asm/sh_keysc.h>
 #include <cpu/sh7724.h>
 #include <mach-se/mach/se7724.h>
@@ -272,6 +274,34 @@ static struct platform_device keysc_device = {
        },
 };
 
+/* SH Eth */
+static struct resource sh_eth_resources[] = {
+       [0] = {
+               .start = SH_ETH_ADDR,
+               .end   = SH_ETH_ADDR + 0x1FC,
+               .flags = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start = 91,
+               .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
+       },
+};
+
+struct sh_eth_plat_data sh_eth_plat = {
+       .phy = 0x1f, /* SMSC LAN8187 */
+       .edmac_endian = EDMAC_LITTLE_ENDIAN,
+};
+
+static struct platform_device sh_eth_device = {
+       .name = "sh-eth",
+       .id     = 0,
+       .dev = {
+               .platform_data = &sh_eth_plat,
+       },
+       .num_resources = ARRAY_SIZE(sh_eth_resources),
+       .resource = sh_eth_resources,
+};
+
 static struct platform_device *ms7724se_devices[] __initdata = {
        &heartbeat_device,
        &smc91x_eth_device,
@@ -280,8 +310,57 @@ static struct platform_device *ms7724se_devices[] __initdata = {
        &ceu0_device,
        &ceu1_device,
        &keysc_device,
+       &sh_eth_device,
 };
 
+#define EEPROM_OP   0xBA206000
+#define EEPROM_ADR  0xBA206004
+#define EEPROM_DATA 0xBA20600C
+#define EEPROM_STAT 0xBA206010
+#define EEPROM_STRT 0xBA206014
+static int __init sh_eth_is_eeprom_ready(void)
+{
+       int t = 10000;
+
+       while (t--) {
+               if (!ctrl_inw(EEPROM_STAT))
+                       return 1;
+               cpu_relax();
+       }
+
+       printk(KERN_ERR "ms7724se can not access to eeprom\n");
+       return 0;
+}
+
+static void __init sh_eth_init(void)
+{
+       int i;
+       u16 mac[3];
+
+       /* check EEPROM status */
+       if (!sh_eth_is_eeprom_ready())
+               return;
+
+       /* read MAC addr from EEPROM */
+       for (i = 0 ; i < 3 ; i++) {
+               ctrl_outw(0x0, EEPROM_OP); /* read */
+               ctrl_outw(i*2, EEPROM_ADR);
+               ctrl_outw(0x1, EEPROM_STRT);
+               if (!sh_eth_is_eeprom_ready())
+                       return;
+
+               mac[i] = ctrl_inw(EEPROM_DATA);
+               mac[i] = ((mac[i] & 0xFF) << 8) | (mac[i] >> 8); /* swap */
+       }
+
+       /* reset sh-eth */
+       ctrl_outl(0x1, SH_ETH_ADDR + 0x0);
+
+       /* set MAC addr */
+       ctrl_outl(((mac[0] << 16) | (mac[1])), SH_ETH_MAHR);
+       ctrl_outl((mac[2]), SH_ETH_MALR);
+}
+
 #define SW4140    0xBA201000
 #define FPGA_OUT  0xBA200400
 #define PORT_HIZA 0xA4050158
@@ -302,7 +381,8 @@ static int __init devices_setup(void)
        ctrl_outw(ctrl_inw(FPGA_OUT) &
                  ~((1 << 1)  | /* LAN */
                    (1 << 6)  | /* VIDEO DAC */
-                   (1 << 12)), /* USB0 */
+                   (1 << 12) | /* USB0 */
+                   (1 << 14)), /* RMII */
                  FPGA_OUT);
 
        /* enable IRQ 0,1,2 */
@@ -374,7 +454,7 @@ static int __init devices_setup(void)
        gpio_request(GPIO_FN_VIO0_CLK, NULL);
        gpio_request(GPIO_FN_VIO0_FLD, NULL);
        gpio_request(GPIO_FN_VIO0_HD,  NULL);
-       platform_resource_setup_memory(&ceu0_device, "ceu", 4 << 20);
+       platform_resource_setup_memory(&ceu0_device, "ceu0", 4 << 20);
 
        /* enable CEU1 */
        gpio_request(GPIO_FN_VIO1_D7,  NULL);
@@ -389,7 +469,7 @@ static int __init devices_setup(void)
        gpio_request(GPIO_FN_VIO1_HD,  NULL);
        gpio_request(GPIO_FN_VIO1_VD,  NULL);
        gpio_request(GPIO_FN_VIO1_CLK, NULL);
-       platform_resource_setup_memory(&ceu1_device, "ceu", 4 << 20);
+       platform_resource_setup_memory(&ceu1_device, "ceu1", 4 << 20);
 
        /* KEYSC */
        gpio_request(GPIO_FN_KEYOUT5_IN5, NULL);
@@ -404,6 +484,28 @@ static int __init devices_setup(void)
        gpio_request(GPIO_FN_KEYOUT1,     NULL);
        gpio_request(GPIO_FN_KEYOUT0,     NULL);
 
+       /*
+        * enable SH-Eth
+        *
+        * please remove J33 pin from your board !!
+        *
+        * ms7724 board should not use GPIO_FN_LNKSTA pin
+        * So, This time PTX5 is set to input pin
+        */
+       gpio_request(GPIO_FN_RMII_RXD0,    NULL);
+       gpio_request(GPIO_FN_RMII_RXD1,    NULL);
+       gpio_request(GPIO_FN_RMII_TXD0,    NULL);
+       gpio_request(GPIO_FN_RMII_TXD1,    NULL);
+       gpio_request(GPIO_FN_RMII_REF_CLK, NULL);
+       gpio_request(GPIO_FN_RMII_TX_EN,   NULL);
+       gpio_request(GPIO_FN_RMII_RX_ER,   NULL);
+       gpio_request(GPIO_FN_RMII_CRS_DV,  NULL);
+       gpio_request(GPIO_FN_MDIO,         NULL);
+       gpio_request(GPIO_FN_MDC,          NULL);
+       gpio_request(GPIO_PTX5, NULL);
+       gpio_direction_input(GPIO_PTX5);
+       sh_eth_init();
+
        if (sw & SW41_B) {
                /* SVGA */
                lcdc_info.ch[0].lcd_cfg.xres         = 800;
@@ -437,7 +539,7 @@ static int __init devices_setup(void)
        }
 
        return platform_add_devices(ms7724se_devices,
-                               ARRAY_SIZE(ms7724se_devices));
+                                   ARRAY_SIZE(ms7724se_devices));
 }
 device_initcall(devices_setup);
 
index da627d2..b18cfd3 100644 (file)
@@ -309,7 +309,7 @@ CONFIG_ZERO_PAGE_OFFSET=0x00001000
 CONFIG_BOOT_LINK_OFFSET=0x00800000
 CONFIG_ENTRY_OFFSET=0x00001000
 CONFIG_CMDLINE_BOOL=y
-CONFIG_CMDLINE="console=ttySC0,115200 earlyprintk=serial ip=on root=/dev/nfs ip=dhcp"
+CONFIG_CMDLINE="console=tty0 console=ttySC0,115200 earlyprintk=serial ip=on root=/dev/nfs ip=dhcp"
 
 #
 # Bus options
@@ -858,7 +858,35 @@ CONFIG_VIDEO_SH_MOBILE_CEU=y
 #
 # CONFIG_VGASTATE is not set
 # CONFIG_VIDEO_OUTPUT_CONTROL is not set
-# CONFIG_FB is not set
+CONFIG_FB=y
+# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_FB_DDC is not set
+# CONFIG_FB_BOOT_VESA_SUPPORT is not set
+# CONFIG_FB_CFB_FILLRECT is not set
+# CONFIG_FB_CFB_COPYAREA is not set
+# CONFIG_FB_CFB_IMAGEBLIT is not set
+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
+CONFIG_FB_SYS_FILLRECT=y
+CONFIG_FB_SYS_COPYAREA=y
+CONFIG_FB_SYS_IMAGEBLIT=y
+# CONFIG_FB_FOREIGN_ENDIAN is not set
+CONFIG_FB_SYS_FOPS=y
+CONFIG_FB_DEFERRED_IO=y
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+
+#
+# Frame buffer hardware drivers
+#
+# CONFIG_FB_S1D13XXX is not set
+CONFIG_FB_SH_MOBILE_LCDC=y
+# CONFIG_FB_VIRTUAL is not set
+# CONFIG_FB_METRONOME is not set
+# CONFIG_FB_MB862XX is not set
+# CONFIG_FB_BROADSHEET is not set
 # CONFIG_BACKLIGHT_LCD_SUPPORT is not set
 
 #
@@ -870,6 +898,27 @@ CONFIG_VIDEO_SH_MOBILE_CEU=y
 # Console display driver support
 #
 CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+CONFIG_FONTS=y
+# CONFIG_FONT_8x8 is not set
+# CONFIG_FONT_8x16 is not set
+# CONFIG_FONT_6x11 is not set
+# CONFIG_FONT_7x14 is not set
+# CONFIG_FONT_PEARL_8x8 is not set
+# CONFIG_FONT_ACORN_8x8 is not set
+CONFIG_FONT_MINI_4x6=y
+# CONFIG_FONT_SUN8x16 is not set
+# CONFIG_FONT_SUN12x22 is not set
+# CONFIG_FONT_10x18 is not set
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+# CONFIG_LOGO_LINUX_CLUT224 is not set
+# CONFIG_LOGO_SUPERH_MONO is not set
+CONFIG_LOGO_SUPERH_VGA16=y
+# CONFIG_LOGO_SUPERH_CLUT224 is not set
 # CONFIG_SOUND is not set
 CONFIG_HID_SUPPORT=y
 CONFIG_HID=y
index 3840270..3ee783a 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
 # Linux kernel version: 2.6.30
-# Thu Jun 18 16:09:05 2009
+# Mon Jun 29 16:28:43 2009
 #
 CONFIG_SUPERH=y
 CONFIG_SUPERH32=y
@@ -14,6 +14,7 @@ CONFIG_GENERIC_HWEIGHT=y
 CONFIG_GENERIC_HARDIRQS=y
 CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
 CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_IRQ_PER_CPU=y
 CONFIG_GENERIC_GPIO=y
 CONFIG_GENERIC_TIME=y
 CONFIG_GENERIC_CLOCKEVENTS=y
@@ -28,7 +29,9 @@ CONFIG_HAVE_LATENCYTOP_SUPPORT=y
 # CONFIG_ARCH_HAS_ILOG2_U64 is not set
 CONFIG_ARCH_NO_VIRT_TO_BUS=y
 CONFIG_ARCH_HAS_DEFAULT_IDLE=y
+CONFIG_ARCH_HAS_CPU_IDLE_WAIT=y
 CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
 
 #
 # General setup
@@ -88,10 +91,12 @@ CONFIG_TIMERFD=y
 CONFIG_EVENTFD=y
 CONFIG_SHMEM=y
 CONFIG_AIO=y
+CONFIG_HAVE_PERF_COUNTERS=y
 
 #
 # Performance Counters
 #
+# CONFIG_PERF_COUNTERS is not set
 CONFIG_VM_EVENT_COUNTERS=y
 # CONFIG_STRIP_ASM_SYMS is not set
 CONFIG_COMPAT_BRK=y
@@ -107,6 +112,10 @@ CONFIG_HAVE_KRETPROBES=y
 CONFIG_HAVE_ARCH_TRACEHOOK=y
 CONFIG_HAVE_CLK=y
 CONFIG_HAVE_DMA_API_DEBUG=y
+
+#
+# GCOV-based kernel profiling
+#
 # CONFIG_SLOW_WORK is not set
 CONFIG_HAVE_GENERIC_DMA_COHERENT=y
 CONFIG_SLABINFO=y
@@ -119,7 +128,7 @@ CONFIG_MODULE_UNLOAD=y
 # CONFIG_MODVERSIONS is not set
 # CONFIG_MODULE_SRCVERSION_ALL is not set
 CONFIG_BLOCK=y
-# CONFIG_LBD is not set
+CONFIG_LBDAF=y
 # CONFIG_BLK_DEV_BSG is not set
 # CONFIG_BLK_DEV_INTEGRITY is not set
 
@@ -584,7 +593,6 @@ CONFIG_SCSI_WAIT_SCAN=m
 # CONFIG_SCSI_SRP_ATTRS is not set
 CONFIG_SCSI_LOWLEVEL=y
 # CONFIG_ISCSI_TCP is not set
-# CONFIG_SCSI_BNX2_ISCSI is not set
 # CONFIG_LIBFC is not set
 # CONFIG_LIBFCOE is not set
 # CONFIG_SCSI_DEBUG is not set
@@ -624,7 +632,7 @@ CONFIG_NET_ETHERNET=y
 CONFIG_MII=y
 # CONFIG_AX88796 is not set
 # CONFIG_STNIC is not set
-# CONFIG_SH_ETH is not set
+CONFIG_SH_ETH=y
 CONFIG_SMC91X=y
 # CONFIG_ENC28J60 is not set
 # CONFIG_ETHOC is not set
@@ -801,6 +809,11 @@ CONFIG_SPI_BITBANG=y
 #
 # CONFIG_SPI_SPIDEV is not set
 # CONFIG_SPI_TLE62X0 is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
 CONFIG_ARCH_REQUIRE_GPIOLIB=y
 CONFIG_GPIOLIB=y
 # CONFIG_GPIO_SYSFS is not set
@@ -851,6 +864,8 @@ CONFIG_SSB_POSSIBLE=y
 # CONFIG_MFD_WM8400 is not set
 # CONFIG_MFD_WM8350_I2C is not set
 # CONFIG_MFD_PCF50633 is not set
+# CONFIG_AB3100_CORE is not set
+# CONFIG_EZX_PCAP is not set
 # CONFIG_REGULATOR is not set
 CONFIG_MEDIA_SUPPORT=y
 
@@ -1196,6 +1211,7 @@ CONFIG_RTC_DRV_PCF8563=y
 # CONFIG_RTC_DRV_S35390A is not set
 # CONFIG_RTC_DRV_FM3130 is not set
 # CONFIG_RTC_DRV_RX8581 is not set
+# CONFIG_RTC_DRV_RX8025 is not set
 
 #
 # SPI RTC drivers
@@ -1260,6 +1276,7 @@ CONFIG_FS_MBCACHE=y
 # CONFIG_JFS_FS is not set
 CONFIG_FS_POSIX_ACL=y
 # CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
 # CONFIG_OCFS2_FS is not set
 # CONFIG_BTRFS_FS is not set
 CONFIG_FILE_LOCKING=y
index a8153c2..61c2b40 100644 (file)
@@ -2,6 +2,6 @@
 #define __ASM_SH_PERF_COUNTER_H
 
 /* SH only supports software counters through this interface. */
-#define set_perf_counter_pending()     do { } while (0)
+static inline void set_perf_counter_pending(void) {}
 
 #endif /* __ASM_SH_PERF_COUNTER_H */
index 5bc3468..6f83f2c 100644 (file)
@@ -3,6 +3,7 @@
 
 #include <linux/kernel.h>
 #include <linux/sched.h>
+#include <linux/err.h>
 #include <asm/ptrace.h>
 
 /* The system call number is given by the user in R3 */
index 74164b6..29514a3 100644 (file)
  */
 #include <asm/addrspace.h>
 
+/* SH Eth */
+#define SH_ETH_ADDR    (0xA4600000)
+#define SH_ETH_MAHR    (SH_ETH_ADDR + 0x1C0)
+#define SH_ETH_MALR    (SH_ETH_ADDR + 0x1C8)
+
 #define PA_LED         (0xba203000)    /* 8bit LED */
 #define IRQ_MODE       (0xba200010)
 #define IRQ0_SR                (0xba200014)
index cc8ddbd..7192594 100644 (file)
 #include <linux/mm.h>
 #include <linux/hardirq.h>
 #include <linux/kprobes.h>
-#include <linux/marker.h>
+#include <linux/perf_counter.h>
 #include <asm/io_trapped.h>
 #include <asm/system.h>
 #include <asm/mmu_context.h>
 #include <asm/tlbflush.h>
 
+static inline int notify_page_fault(struct pt_regs *regs, int trap)
+{
+       int ret = 0;
+
+#ifdef CONFIG_KPROBES
+       if (!user_mode(regs)) {
+               preempt_disable();
+               if (kprobe_running() && kprobe_fault_handler(regs, trap))
+                       ret = 1;
+               preempt_enable();
+       }
+#endif
+
+       return ret;
+}
+
 /*
  * This routine handles page faults.  It determines the address,
  * and the problem, and then passes it off to one of the appropriate
@@ -87,13 +103,16 @@ asmlinkage void __kprobes do_page_fault(struct pt_regs *regs,
                return;
        }
 
+       mm = tsk->mm;
+
+       if (unlikely(notify_page_fault(regs, lookup_exception_vector())))
+               return;
+
        /* Only enable interrupts if they were on before the fault */
-       if ((regs->sr & SR_IMASK) != SR_IMASK) {
-               trace_hardirqs_on();
+       if ((regs->sr & SR_IMASK) != SR_IMASK)
                local_irq_enable();
-       }
 
-       mm = tsk->mm;
+       perf_swcounter_event(PERF_COUNT_SW_PAGE_FAULTS, 1, 0, regs, address);
 
        /*
         * If we're in an interrupt or have no user
@@ -141,10 +160,15 @@ survive:
                        goto do_sigbus;
                BUG();
        }
-       if (fault & VM_FAULT_MAJOR)
+       if (fault & VM_FAULT_MAJOR) {
                tsk->maj_flt++;
-       else
+               perf_swcounter_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1, 0,
+                                    regs, address);
+       } else {
                tsk->min_flt++;
+               perf_swcounter_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1, 0,
+                                    regs, address);
+       }
 
        up_read(&mm->mmap_sem);
        return;
@@ -245,22 +269,6 @@ do_sigbus:
                goto no_context;
 }
 
-static inline int notify_page_fault(struct pt_regs *regs, int trap)
-{
-       int ret = 0;
-
-#ifdef CONFIG_KPROBES
-       if (!user_mode(regs)) {
-               preempt_disable();
-               if (kprobe_running() && kprobe_fault_handler(regs, trap))
-                       ret = 1;
-               preempt_enable();
-       }
-#endif
-
-       return ret;
-}
-
 /*
  * Called with interrupts disabled.
  */
@@ -273,12 +281,7 @@ asmlinkage int __kprobes __do_page_fault(struct pt_regs *regs,
        pmd_t *pmd;
        pte_t *pte;
        pte_t entry;
-       int ret = 0;
-
-       if (notify_page_fault(regs, lookup_exception_vector()))
-               goto out;
-
-       ret = 1;
+       int ret = 1;
 
        /*
         * We don't take page faults for P1, P2, and parts of P4, these
index fcbb6e1..3ce40ea 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (C) 2000, 2001  Paolo Alberelli
  * Copyright (C) 2003  Richard Curnow (/proc/tlb, bug fixes)
- * Copyright (C) 2003  Paul Mundt
+ * Copyright (C) 2003 - 2009 Paul Mundt
  *
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
@@ -20,6 +20,7 @@
 #include <linux/mman.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
+#include <linux/perf_counter.h>
 #include <linux/interrupt.h>
 #include <asm/system.h>
 #include <asm/io.h>
@@ -115,6 +116,8 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long writeaccess,
        /* Not an IO address, so reenable interrupts */
        local_irq_enable();
 
+       perf_swcounter_event(PERF_COUNT_SW_PAGE_FAULTS, 1, 0, regs, address);
+
        /*
         * If we're in an interrupt or have no user
         * context, we must not take the fault..
@@ -195,10 +198,16 @@ survive:
                        goto do_sigbus;
                BUG();
        }
-       if (fault & VM_FAULT_MAJOR)
+
+       if (fault & VM_FAULT_MAJOR) {
                tsk->maj_flt++;
-       else
+               perf_swcounter_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1, 0,
+                                    regs, address);
+       } else {
                tsk->min_flt++;
+               perf_swcounter_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1, 0,
+                                    regs, address);
+       }
 
        /* If we get here, the page fault has been handled.  Do the TLB refill
           now from the newly-setup PTE, to avoid having to fault again right
index 96041a8..1ff0fd9 100644 (file)
@@ -15,7 +15,7 @@ quiet_cmd_elftoaout   = ELFTOAOUT $@
 
 ifeq ($(CONFIG_SPARC32),y)
 quiet_cmd_piggy                = PIGGY   $@
-      cmd_piggy                = $(obj)/piggyback_32 $@ $(obj)/System.map $(ROOT_IMG)
+      cmd_piggy                = $(obj)/piggyback_32 $@ System.map $(ROOT_IMG)
 quiet_cmd_btfix                = BTFIX   $@
       cmd_btfix                = $(OBJDUMP) -x vmlinux | $(obj)/btfixupprep > $@
 quiet_cmd_sysmap        = SYSMAP  $(obj)/System.map
@@ -58,7 +58,7 @@ $(obj)/image: $(obj)/btfix.o FORCE
 $(obj)/zImage: $(obj)/image
        $(call if_changed,strip)
 
-$(obj)/tftpboot.img: $(obj)/piggyback $(obj)/System.map $(obj)/image FORCE
+$(obj)/tftpboot.img: $(obj)/image $(obj)/piggyback_32 System.map $(ROOT_IMG) FORCE
        $(call if_changed,elftoaout)
        $(call if_changed,piggy)
 
@@ -79,7 +79,7 @@ $(obj)/image: vmlinux FORCE
        $(call if_changed,strip)
        @echo '  kernel: $@ is ready'
 
-$(obj)/tftpboot.img: vmlinux $(obj)/piggyback_64 System.map $(ROOT_IMG) FORCE
+$(obj)/tftpboot.img: $(obj)/image $(obj)/piggyback_64 System.map $(ROOT_IMG) FORCE
        $(call if_changed,elftoaout)
        $(call if_changed,piggy)
        @echo '  kernel: $@ is ready'
index c9f500c..e8dc9ad 100644 (file)
@@ -70,7 +70,7 @@ void die(char *str)
 int main(int argc,char **argv)
 {
        static char aout_magic[] = { 0x01, 0x03, 0x01, 0x07 };
-       unsigned char buffer[1024], *q, *r;
+       char buffer[1024], *q, *r;
        unsigned int i, j, k, start, end, offset;
        FILE *map;
        struct stat s;
@@ -84,7 +84,7 @@ int main(int argc,char **argv)
        while (fgets (buffer, 1024, map)) {
                if (!strcmp (buffer + 8, " T start\n") || !strcmp (buffer + 16, " T start\n"))
                        start = strtoul (buffer, NULL, 16);
-               else if (!strcmp (buffer + 8, " A end\n") || !strcmp (buffer + 16, " A end\n"))
+               else if (!strcmp (buffer + 8, " A _end\n") || !strcmp (buffer + 16, " A _end\n"))
                        end = strtoul (buffer, NULL, 16);
        }
        fclose (map);
index de364bf..c63fd1b 100644 (file)
@@ -46,6 +46,7 @@ int main(int argc,char **argv)
        struct stat s;
        int image, tail;
        
+       start = end = 0;
        if (stat (argv[3], &s) < 0) die (argv[3]);
        map = fopen (argv[2], "r");
        if (!map) die(argv[2]);
index bd07505..f0ee790 100644 (file)
@@ -20,7 +20,6 @@
 #include <linux/delay.h>
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
-#include <linux/bootmem.h>
 #include <linux/irq.h>
 
 #include <asm/ptrace.h>
@@ -914,25 +913,19 @@ void __cpuinit notrace sun4v_register_mondo_queues(int this_cpu)
                           tb->nonresum_qmask);
 }
 
-static void __init alloc_one_mondo(unsigned long *pa_ptr, unsigned long qmask)
-{
-       unsigned long size = PAGE_ALIGN(qmask + 1);
-       void *p = __alloc_bootmem(size, size, 0);
-       if (!p) {
-               prom_printf("SUN4V: Error, cannot allocate mondo queue.\n");
-               prom_halt();
-       }
-
-       *pa_ptr = __pa(p);
-}
-
-static void __init alloc_one_kbuf(unsigned long *pa_ptr, unsigned long qmask)
+/* Each queue region must be a power of 2 multiple of 64 bytes in
+ * size.  The base real address must be aligned to the size of the
+ * region.  Thus, an 8KB queue must be 8KB aligned, for example.
+ */
+static void __init alloc_one_queue(unsigned long *pa_ptr, unsigned long qmask)
 {
        unsigned long size = PAGE_ALIGN(qmask + 1);
-       void *p = __alloc_bootmem(size, size, 0);
+       unsigned long order = get_order(size);
+       unsigned long p;
 
+       p = __get_free_pages(GFP_KERNEL, order);
        if (!p) {
-               prom_printf("SUN4V: Error, cannot allocate kbuf page.\n");
+               prom_printf("SUN4V: Error, cannot allocate queue.\n");
                prom_halt();
        }
 
@@ -942,11 +935,11 @@ static void __init alloc_one_kbuf(unsigned long *pa_ptr, unsigned long qmask)
 static void __init init_cpu_send_mondo_info(struct trap_per_cpu *tb)
 {
 #ifdef CONFIG_SMP
-       void *page;
+       unsigned long page;
 
        BUILD_BUG_ON((NR_CPUS * sizeof(u16)) > (PAGE_SIZE - 64));
 
-       page = alloc_bootmem_pages(PAGE_SIZE);
+       page = get_zeroed_page(GFP_KERNEL);
        if (!page) {
                prom_printf("SUN4V: Error, cannot allocate cpu mondo page.\n");
                prom_halt();
@@ -965,13 +958,13 @@ static void __init sun4v_init_mondo_queues(void)
        for_each_possible_cpu(cpu) {
                struct trap_per_cpu *tb = &trap_block[cpu];
 
-               alloc_one_mondo(&tb->cpu_mondo_pa, tb->cpu_mondo_qmask);
-               alloc_one_mondo(&tb->dev_mondo_pa, tb->dev_mondo_qmask);
-               alloc_one_mondo(&tb->resum_mondo_pa, tb->resum_qmask);
-               alloc_one_kbuf(&tb->resum_kernel_buf_pa, tb->resum_qmask);
-               alloc_one_mondo(&tb->nonresum_mondo_pa, tb->nonresum_qmask);
-               alloc_one_kbuf(&tb->nonresum_kernel_buf_pa,
-                              tb->nonresum_qmask);
+               alloc_one_queue(&tb->cpu_mondo_pa, tb->cpu_mondo_qmask);
+               alloc_one_queue(&tb->dev_mondo_pa, tb->dev_mondo_qmask);
+               alloc_one_queue(&tb->resum_mondo_pa, tb->resum_qmask);
+               alloc_one_queue(&tb->resum_kernel_buf_pa, tb->resum_qmask);
+               alloc_one_queue(&tb->nonresum_mondo_pa, tb->nonresum_qmask);
+               alloc_one_queue(&tb->nonresum_kernel_buf_pa,
+                               tb->nonresum_qmask);
        }
 }
 
@@ -999,7 +992,7 @@ void __init init_IRQ(void)
        kill_prom_timer();
 
        size = sizeof(struct ino_bucket) * NUM_IVECS;
-       ivector_table = alloc_bootmem(size);
+       ivector_table = kzalloc(size, GFP_KERNEL);
        if (!ivector_table) {
                prom_printf("Fatal error, cannot allocate ivector_table\n");
                prom_halt();
index f061c4d..3762f6c 100644 (file)
@@ -121,7 +121,7 @@ SIGN2(sys32_syslog, sys_syslog, %o0, %o2)
 SIGN1(sys32_umask, sys_umask, %o0)
 SIGN3(sys32_tgkill, sys_tgkill, %o0, %o1, %o2)
 SIGN1(sys32_sendto, sys_sendto, %o0)
-SIGN1(sys32_recvfrom, sys_recvfrom, %o0)
+SIGN1(sys32_recvfrom, compat_sys_recvfrom, %o0)
 SIGN3(sys32_socket, sys_socket, %o0, %o1, %o2)
 SIGN2(sys32_connect, sys_connect, %o0, %o2)
 SIGN2(sys32_bind, sys_bind, %o0, %o2)
index 3b44b47..4c75409 100644 (file)
@@ -245,7 +245,7 @@ static int uml_net_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
        dev_kfree_skb(skb);
 
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 static void uml_net_set_multicast_list(struct net_device *dev)
index 5ec1756..dd2aadc 100644 (file)
@@ -30,7 +30,6 @@ static void slip_init(struct net_device *dev, void *data)
 
        slip_proto_init(&spri->slip);
 
-       dev->init = NULL;
        dev->hard_header_len = 0;
        dev->header_ops = NULL;
        dev->addr_len = 0;
index f15a6e7..e376284 100644 (file)
@@ -32,7 +32,6 @@ void slirp_init(struct net_device *dev, void *data)
 
        slip_proto_init(&spri->slip);
 
-       dev->init = NULL;
        dev->hard_header_len = 0;
        dev->header_ops = NULL;
        dev->addr_len = 0;
index 90fc708..378de4b 100644 (file)
@@ -79,14 +79,14 @@ dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries,
 }
 
 static inline void
-dma_sync_single(struct device *dev, dma_addr_t dma_handle, size_t size,
+dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, size_t size,
                enum dma_data_direction direction)
 {
        BUG();
 }
 
 static inline void
-dma_sync_sg(struct device *dev, struct scatterlist *sg, int nelems,
+dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems,
            enum dma_data_direction direction)
 {
        BUG();
index d1430ef..c07f722 100644 (file)
@@ -1913,25 +1913,14 @@ config DMAR_DEFAULT_ON
          recommended you say N here while the DMAR code remains
          experimental.
 
-config DMAR_GFX_WA
-       def_bool y
-       prompt "Support for Graphics workaround"
-       depends on DMAR
-       ---help---
-         Current Graphics drivers tend to use physical address
-         for DMA and avoid using DMA APIs. Setting this config
-         option permits the IOMMU driver to set a unity map for
-         all the OS-visible memory. Hence the driver can continue
-         to use physical addresses for DMA.
-
 config DMAR_FLOPPY_WA
        def_bool y
        depends on DMAR
        ---help---
-         Floppy disk drivers are know to bypass DMA API calls
+         Floppy disk drivers are known to bypass DMA API calls
          thereby failing to work when IOMMU is enabled. This
          workaround will setup a 1:1 mapping for the first
-         16M to make floppy (an ISA device) work.
+         16MiB to make floppy (an ISA device) work.
 
 config INTR_REMAP
        bool "Support for Interrupt Remapping (EXPERIMENTAL)"
index 418e632..7a10659 100644 (file)
@@ -8,7 +8,7 @@
 
 #ifdef __KERNEL__
 
-#include <asm/page_types.h>
+#include <asm/pgtable_types.h>
 
 /* Physical address where kernel should be loaded. */
 #define LOAD_PHYSICAL_ADDR ((CONFIG_PHYSICAL_START \
                                & ~(CONFIG_PHYSICAL_ALIGN - 1))
 
 /* Minimum kernel alignment, as a power of two */
-#ifdef CONFIG_x86_64
+#ifdef CONFIG_X86_64
 #define MIN_KERNEL_ALIGN_LG2   PMD_SHIFT
 #else
-#define MIN_KERNEL_ALIGN_LG2   (PAGE_SHIFT+1)
+#define MIN_KERNEL_ALIGN_LG2   (PAGE_SHIFT + THREAD_ORDER)
 #endif
 #define MIN_KERNEL_ALIGN       (_AC(1, UL) << MIN_KERNEL_ALIGN_LG2)
 
index 927958d..1ff685c 100644 (file)
@@ -91,7 +91,7 @@ extern void pci_iommu_alloc(void);
 
 #define PCI_DMA_BUS_IS_PHYS (dma_ops->is_phys)
 
-#if defined(CONFIG_X86_64) || defined(CONFIG_DMA_API_DEBUG)
+#if defined(CONFIG_X86_64) || defined(CONFIG_DMAR) || defined(CONFIG_DMA_API_DEBUG)
 
 #define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)       \
                dma_addr_t ADDR_NAME;
index 02ecb30..103f1dd 100644 (file)
@@ -42,6 +42,7 @@
 
 #else /* ...!ASSEMBLY */
 
+#include <linux/kernel.h>
 #include <linux/stringify.h>
 
 #ifdef CONFIG_SMP
@@ -155,6 +156,15 @@ do {                                                       \
 /* We can use this directly for local CPU (faster). */
 DECLARE_PER_CPU(unsigned long, this_cpu_off);
 
+#ifdef CONFIG_NEED_MULTIPLE_NODES
+void *pcpu_lpage_remapped(void *kaddr);
+#else
+static inline void *pcpu_lpage_remapped(void *kaddr)
+{
+       return NULL;
+}
+#endif
+
 #endif /* !__ASSEMBLY__ */
 
 #ifdef CONFIG_SMP
index 5fb33e1..fa64e40 100644 (file)
@@ -87,6 +87,9 @@ union cpuid10_edx {
 #ifdef CONFIG_PERF_COUNTERS
 extern void init_hw_perf_counters(void);
 extern void perf_counters_lapic_init(void);
+
+#define PERF_COUNTER_INDEX_OFFSET                      0
+
 #else
 static inline void init_hw_perf_counters(void)         { }
 static inline void perf_counters_lapic_init(void)      { }
index 49fb3ec..621f56d 100644 (file)
@@ -22,7 +22,14 @@ extern int reboot_force;
 
 long do_arch_prctl(struct task_struct *task, int code, unsigned long addr);
 
-#define round_up(x, y) (((x) + (y) - 1) & ~((y) - 1))
-#define round_down(x, y) ((x) & ~((y) - 1))
+/*
+ * This looks more complex than it should be. But we need to
+ * get the type for the ~ right in round_down (it needs to be
+ * as wide as the result!), and we want to evaluate the macro
+ * arguments just once each.
+ */
+#define __round_mask(x,y) ((__typeof__(x))((y)-1))
+#define round_up(x,y) ((((x)-1) | __round_mask(x,y))+1)
+#define round_down(x,y) ((x) & ~__round_mask(x,y))
 
 #endif /* _ASM_X86_PROTO_H */
index e5b27d8..28e5f59 100644 (file)
@@ -258,13 +258,15 @@ static void __cpuinit amd_detect_cmp(struct cpuinfo_x86 *c)
 {
 #ifdef CONFIG_X86_HT
        unsigned bits;
+       int cpu = smp_processor_id();
 
        bits = c->x86_coreid_bits;
-
        /* Low order bits define the core id (index of core in socket) */
        c->cpu_core_id = c->initial_apicid & ((1 << bits)-1);
        /* Convert the initial APIC ID into the socket ID */
        c->phys_proc_id = c->initial_apicid >> bits;
+       /* use socket ID also for last level cache */
+       per_cpu(cpu_llc_id, cpu) = c->phys_proc_id;
 #endif
 }
 
index 6b26d4d..f1961c0 100644 (file)
@@ -848,9 +848,6 @@ static void __cpuinit identify_cpu(struct cpuinfo_x86 *c)
 #if defined(CONFIG_NUMA) && defined(CONFIG_X86_64)
        numa_add_cpu(smp_processor_id());
 #endif
-
-       /* Cap the iomem address space to what is addressable on all CPUs */
-       iomem_resource.end &= (1ULL << c->x86_phys_bits) - 1;
 }
 
 #ifdef CONFIG_X86_64
index 284d1de..af425b8 100644 (file)
@@ -1117,7 +1117,7 @@ static void mcheck_timer(unsigned long data)
                *n = min(*n*2, (int)round_jiffies_relative(check_interval*HZ));
 
        t->expires = jiffies + *n;
-       add_timer(t);
+       add_timer_on(t, smp_processor_id());
 }
 
 static void mce_do_trigger(struct work_struct *work)
@@ -1321,7 +1321,7 @@ static void mce_init_timer(void)
                return;
        setup_timer(t, mcheck_timer, smp_processor_id());
        t->expires = round_jiffies(jiffies + *n);
-       add_timer(t);
+       add_timer_on(t, smp_processor_id());
 }
 
 /*
index 76dfef2..d4cf4ce 100644 (file)
@@ -401,7 +401,7 @@ static const u64 amd_hw_cache_event_ids
                [ C(RESULT_MISS)   ] = 0x0041, /* Data Cache Misses          */
        },
        [ C(OP_WRITE) ] = {
-               [ C(RESULT_ACCESS) ] = 0x0042, /* Data Cache Refills from L2 */
+               [ C(RESULT_ACCESS) ] = 0x0142, /* Data Cache Refills :system */
                [ C(RESULT_MISS)   ] = 0,
        },
        [ C(OP_PREFETCH) ] = {
@@ -912,6 +912,8 @@ x86_perf_counter_set_period(struct perf_counter *counter,
        err = checking_wrmsrl(hwc->counter_base + idx,
                             (u64)(-left) & x86_pmu.counter_mask);
 
+       perf_counter_update_userpage(counter);
+
        return ret;
 }
 
@@ -969,13 +971,6 @@ fixed_mode_idx(struct perf_counter *counter, struct hw_perf_counter *hwc)
        if (!x86_pmu.num_counters_fixed)
                return -1;
 
-       /*
-        * Quirk, IA32_FIXED_CTRs do not work on current Atom processors:
-        */
-       if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL &&
-                                       boot_cpu_data.x86_model == 28)
-               return -1;
-
        event = hwc->config & ARCH_PERFMON_EVENT_MASK;
 
        if (unlikely(event == x86_pmu.event_map(PERF_COUNT_HW_INSTRUCTIONS)))
@@ -1041,6 +1036,8 @@ try_generic:
        x86_perf_counter_set_period(counter, hwc, idx);
        x86_pmu.enable(hwc, idx);
 
+       perf_counter_update_userpage(counter);
+
        return 0;
 }
 
@@ -1133,6 +1130,8 @@ static void x86_pmu_disable(struct perf_counter *counter)
        x86_perf_counter_update(counter, hwc, idx);
        cpuc->counters[idx] = NULL;
        clear_bit(idx, cpuc->used_mask);
+
+       perf_counter_update_userpage(counter);
 }
 
 /*
@@ -1428,8 +1427,6 @@ static int intel_pmu_init(void)
         */
        x86_pmu.num_counters_fixed      = max((int)edx.split.num_counters_fixed, 3);
 
-       rdmsrl(MSR_CORE_PERF_GLOBAL_CTRL, x86_pmu.intel_ctrl);
-
        /*
         * Install the hw-cache-events table:
         */
@@ -1499,21 +1496,22 @@ void __init init_hw_perf_counters(void)
        pr_cont("%s PMU driver.\n", x86_pmu.name);
 
        if (x86_pmu.num_counters > X86_PMC_MAX_GENERIC) {
-               x86_pmu.num_counters = X86_PMC_MAX_GENERIC;
                WARN(1, KERN_ERR "hw perf counters %d > max(%d), clipping!",
                     x86_pmu.num_counters, X86_PMC_MAX_GENERIC);
+               x86_pmu.num_counters = X86_PMC_MAX_GENERIC;
        }
        perf_counter_mask = (1 << x86_pmu.num_counters) - 1;
        perf_max_counters = x86_pmu.num_counters;
 
        if (x86_pmu.num_counters_fixed > X86_PMC_MAX_FIXED) {
-               x86_pmu.num_counters_fixed = X86_PMC_MAX_FIXED;
                WARN(1, KERN_ERR "hw perf counters fixed %d > max(%d), clipping!",
                     x86_pmu.num_counters_fixed, X86_PMC_MAX_FIXED);
+               x86_pmu.num_counters_fixed = X86_PMC_MAX_FIXED;
        }
 
        perf_counter_mask |=
                ((1LL << x86_pmu.num_counters_fixed)-1) << X86_PMC_IDX_FIXED;
+       x86_pmu.intel_ctrl = perf_counter_mask;
 
        perf_counters_lapic_init();
        register_die_notifier(&perf_counter_nmi_notifier);
index 95ea5fa..c840571 100644 (file)
@@ -22,6 +22,7 @@
 #include "dumpstack.h"
 
 int panic_on_unrecovered_nmi;
+int panic_on_io_nmi;
 unsigned int code_bytes = 64;
 int kstack_depth_to_print = 3 * STACKSLOTS_PER_LINE;
 static int die_counter;
index 7271fa3..c4ca89d 100644 (file)
@@ -1383,6 +1383,8 @@ static unsigned long ram_alignment(resource_size_t pos)
        return 32*1024*1024;
 }
 
+#define MAX_RESOURCE_SIZE ((resource_size_t)-1)
+
 void __init e820_reserve_resources_late(void)
 {
        int i;
@@ -1400,17 +1402,19 @@ void __init e820_reserve_resources_late(void)
         * avoid stolen RAM:
         */
        for (i = 0; i < e820.nr_map; i++) {
-               struct e820entry *entry = &e820_saved.map[i];
-               resource_size_t start, end;
+               struct e820entry *entry = &e820.map[i];
+               u64 start, end;
 
                if (entry->type != E820_RAM)
                        continue;
                start = entry->addr + entry->size;
-               end = round_up(start, ram_alignment(start));
-               if (start == end)
+               end = round_up(start, ram_alignment(start)) - 1;
+               if (end > MAX_RESOURCE_SIZE)
+                       end = MAX_RESOURCE_SIZE;
+               if (start >= end)
                        continue;
-               reserve_region_with_split(&iomem_resource, start,
-                                                 end - 1, "RAM buffer");
+               reserve_region_with_split(&iomem_resource, start, end,
+                                         "RAM buffer");
        }
 }
 
index 4763047..1a041bc 100644 (file)
@@ -211,11 +211,11 @@ static __init int iommu_setup(char *p)
 #ifdef CONFIG_SWIOTLB
                if (!strncmp(p, "soft", 4))
                        swiotlb = 1;
+#endif
                if (!strncmp(p, "pt", 2)) {
                        iommu_pass_through = 1;
                        return 1;
                }
-#endif
 
                gart_parse_options(p);
 
index be5ae80..de2cab1 100644 (file)
@@ -289,6 +289,20 @@ void * __init extend_brk(size_t size, size_t align)
        return ret;
 }
 
+#ifdef CONFIG_X86_64
+static void __init init_gbpages(void)
+{
+       if (direct_gbpages && cpu_has_gbpages)
+               printk(KERN_INFO "Using GB pages for direct mapping\n");
+       else
+               direct_gbpages = 0;
+}
+#else
+static inline void init_gbpages(void)
+{
+}
+#endif
+
 static void __init reserve_brk(void)
 {
        if (_brk_end > _brk_start)
@@ -871,6 +885,8 @@ void __init setup_arch(char **cmdline_p)
 
        reserve_brk();
 
+       init_gbpages();
+
        /* max_pfn_mapped is updated here */
        max_low_pfn_mapped = init_memory_mapping(0, max_low_pfn<<PAGE_SHIFT);
        max_pfn_mapped = max_low_pfn_mapped;
index 9c3f082..29a3eef 100644 (file)
@@ -124,7 +124,7 @@ static void * __init pcpu_alloc_bootmem(unsigned int cpu, unsigned long size,
 }
 
 /*
- * Remap allocator
+ * Large page remap allocator
  *
  * This allocator uses PMD page as unit.  A PMD page is allocated for
  * each cpu and each is remapped into vmalloc area using PMD mapping.
@@ -137,105 +137,185 @@ static void * __init pcpu_alloc_bootmem(unsigned int cpu, unsigned long size,
  * better than only using 4k mappings while still being NUMA friendly.
  */
 #ifdef CONFIG_NEED_MULTIPLE_NODES
-static size_t pcpur_size __initdata;
-static void **pcpur_ptrs __initdata;
+struct pcpul_ent {
+       unsigned int    cpu;
+       void            *ptr;
+};
+
+static size_t pcpul_size;
+static struct pcpul_ent *pcpul_map;
+static struct vm_struct pcpul_vm;
 
-static struct page * __init pcpur_get_page(unsigned int cpu, int pageno)
+static struct page * __init pcpul_get_page(unsigned int cpu, int pageno)
 {
        size_t off = (size_t)pageno << PAGE_SHIFT;
 
-       if (off >= pcpur_size)
+       if (off >= pcpul_size)
                return NULL;
 
-       return virt_to_page(pcpur_ptrs[cpu] + off);
+       return virt_to_page(pcpul_map[cpu].ptr + off);
 }
 
-static ssize_t __init setup_pcpu_remap(size_t static_size)
+static ssize_t __init setup_pcpu_lpage(size_t static_size, bool chosen)
 {
-       static struct vm_struct vm;
-       size_t ptrs_size, dyn_size;
+       size_t map_size, dyn_size;
        unsigned int cpu;
+       int i, j;
        ssize_t ret;
 
-       /*
-        * If large page isn't supported, there's no benefit in doing
-        * this.  Also, on non-NUMA, embedding is better.
-        *
-        * NOTE: disabled for now.
-        */
-       if (true || !cpu_has_pse || !pcpu_need_numa())
+       if (!chosen) {
+               size_t vm_size = VMALLOC_END - VMALLOC_START;
+               size_t tot_size = num_possible_cpus() * PMD_SIZE;
+
+               /* on non-NUMA, embedding is better */
+               if (!pcpu_need_numa())
+                       return -EINVAL;
+
+               /* don't consume more than 20% of vmalloc area */
+               if (tot_size > vm_size / 5) {
+                       pr_info("PERCPU: too large chunk size %zuMB for "
+                               "large page remap\n", tot_size >> 20);
+                       return -EINVAL;
+               }
+       }
+
+       /* need PSE */
+       if (!cpu_has_pse) {
+               pr_warning("PERCPU: lpage allocator requires PSE\n");
                return -EINVAL;
+       }
 
        /*
         * Currently supports only single page.  Supporting multiple
         * pages won't be too difficult if it ever becomes necessary.
         */
-       pcpur_size = PFN_ALIGN(static_size + PERCPU_MODULE_RESERVE +
+       pcpul_size = PFN_ALIGN(static_size + PERCPU_MODULE_RESERVE +
                               PERCPU_DYNAMIC_RESERVE);
-       if (pcpur_size > PMD_SIZE) {
+       if (pcpul_size > PMD_SIZE) {
                pr_warning("PERCPU: static data is larger than large page, "
                           "can't use large page\n");
                return -EINVAL;
        }
-       dyn_size = pcpur_size - static_size - PERCPU_FIRST_CHUNK_RESERVE;
+       dyn_size = pcpul_size - static_size - PERCPU_FIRST_CHUNK_RESERVE;
 
        /* allocate pointer array and alloc large pages */
-       ptrs_size = PFN_ALIGN(num_possible_cpus() * sizeof(pcpur_ptrs[0]));
-       pcpur_ptrs = alloc_bootmem(ptrs_size);
+       map_size = PFN_ALIGN(num_possible_cpus() * sizeof(pcpul_map[0]));
+       pcpul_map = alloc_bootmem(map_size);
 
        for_each_possible_cpu(cpu) {
-               pcpur_ptrs[cpu] = pcpu_alloc_bootmem(cpu, PMD_SIZE, PMD_SIZE);
-               if (!pcpur_ptrs[cpu])
+               pcpul_map[cpu].cpu = cpu;
+               pcpul_map[cpu].ptr = pcpu_alloc_bootmem(cpu, PMD_SIZE,
+                                                       PMD_SIZE);
+               if (!pcpul_map[cpu].ptr) {
+                       pr_warning("PERCPU: failed to allocate large page "
+                                  "for cpu%u\n", cpu);
                        goto enomem;
+               }
 
                /*
-                * Only use pcpur_size bytes and give back the rest.
+                * Only use pcpul_size bytes and give back the rest.
                 *
                 * Ingo: The 2MB up-rounding bootmem is needed to make
                 * sure the partial 2MB page is still fully RAM - it's
                 * not well-specified to have a PAT-incompatible area
                 * (unmapped RAM, device memory, etc.) in that hole.
                 */
-               free_bootmem(__pa(pcpur_ptrs[cpu] + pcpur_size),
-                            PMD_SIZE - pcpur_size);
+               free_bootmem(__pa(pcpul_map[cpu].ptr + pcpul_size),
+                            PMD_SIZE - pcpul_size);
 
-               memcpy(pcpur_ptrs[cpu], __per_cpu_load, static_size);
+               memcpy(pcpul_map[cpu].ptr, __per_cpu_load, static_size);
        }
 
        /* allocate address and map */
-       vm.flags = VM_ALLOC;
-       vm.size = num_possible_cpus() * PMD_SIZE;
-       vm_area_register_early(&vm, PMD_SIZE);
+       pcpul_vm.flags = VM_ALLOC;
+       pcpul_vm.size = num_possible_cpus() * PMD_SIZE;
+       vm_area_register_early(&pcpul_vm, PMD_SIZE);
 
        for_each_possible_cpu(cpu) {
-               pmd_t *pmd;
+               pmd_t *pmd, pmd_v;
 
-               pmd = populate_extra_pmd((unsigned long)vm.addr
-                                        + cpu * PMD_SIZE);
-               set_pmd(pmd, pfn_pmd(page_to_pfn(virt_to_page(pcpur_ptrs[cpu])),
-                                    PAGE_KERNEL_LARGE));
+               pmd = populate_extra_pmd((unsigned long)pcpul_vm.addr +
+                                        cpu * PMD_SIZE);
+               pmd_v = pfn_pmd(page_to_pfn(virt_to_page(pcpul_map[cpu].ptr)),
+                               PAGE_KERNEL_LARGE);
+               set_pmd(pmd, pmd_v);
        }
 
        /* we're ready, commit */
        pr_info("PERCPU: Remapped at %p with large pages, static data "
-               "%zu bytes\n", vm.addr, static_size);
+               "%zu bytes\n", pcpul_vm.addr, static_size);
 
-       ret = pcpu_setup_first_chunk(pcpur_get_page, static_size,
+       ret = pcpu_setup_first_chunk(pcpul_get_page, static_size,
                                     PERCPU_FIRST_CHUNK_RESERVE, dyn_size,
-                                    PMD_SIZE, vm.addr, NULL);
-       goto out_free_ar;
+                                    PMD_SIZE, pcpul_vm.addr, NULL);
+
+       /* sort pcpul_map array for pcpu_lpage_remapped() */
+       for (i = 0; i < num_possible_cpus() - 1; i++)
+               for (j = i + 1; j < num_possible_cpus(); j++)
+                       if (pcpul_map[i].ptr > pcpul_map[j].ptr) {
+                               struct pcpul_ent tmp = pcpul_map[i];
+                               pcpul_map[i] = pcpul_map[j];
+                               pcpul_map[j] = tmp;
+                       }
+
+       return ret;
 
 enomem:
        for_each_possible_cpu(cpu)
-               if (pcpur_ptrs[cpu])
-                       free_bootmem(__pa(pcpur_ptrs[cpu]), PMD_SIZE);
-       ret = -ENOMEM;
-out_free_ar:
-       free_bootmem(__pa(pcpur_ptrs), ptrs_size);
-       return ret;
+               if (pcpul_map[cpu].ptr)
+                       free_bootmem(__pa(pcpul_map[cpu].ptr), pcpul_size);
+       free_bootmem(__pa(pcpul_map), map_size);
+       return -ENOMEM;
+}
+
+/**
+ * pcpu_lpage_remapped - determine whether a kaddr is in pcpul recycled area
+ * @kaddr: the kernel address in question
+ *
+ * Determine whether @kaddr falls in the pcpul recycled area.  This is
+ * used by pageattr to detect VM aliases and break up the pcpu PMD
+ * mapping such that the same physical page is not mapped under
+ * different attributes.
+ *
+ * The recycled area is always at the tail of a partially used PMD
+ * page.
+ *
+ * RETURNS:
+ * Address of corresponding remapped pcpu address if match is found;
+ * otherwise, NULL.
+ */
+void *pcpu_lpage_remapped(void *kaddr)
+{
+       void *pmd_addr = (void *)((unsigned long)kaddr & PMD_MASK);
+       unsigned long offset = (unsigned long)kaddr & ~PMD_MASK;
+       int left = 0, right = num_possible_cpus() - 1;
+       int pos;
+
+       /* pcpul in use at all? */
+       if (!pcpul_map)
+               return NULL;
+
+       /* okay, perform binary search */
+       while (left <= right) {
+               pos = (left + right) / 2;
+
+               if (pcpul_map[pos].ptr < pmd_addr)
+                       left = pos + 1;
+               else if (pcpul_map[pos].ptr > pmd_addr)
+                       right = pos - 1;
+               else {
+                       /* it shouldn't be in the area for the first chunk */
+                       WARN_ON(offset < pcpul_size);
+
+                       return pcpul_vm.addr +
+                               pcpul_map[pos].cpu * PMD_SIZE + offset;
+               }
+       }
+
+       return NULL;
 }
 #else
-static ssize_t __init setup_pcpu_remap(size_t static_size)
+static ssize_t __init setup_pcpu_lpage(size_t static_size, bool chosen)
 {
        return -EINVAL;
 }
@@ -249,7 +329,7 @@ static ssize_t __init setup_pcpu_remap(size_t static_size)
  * mapping so that it can use PMD mapping without additional TLB
  * pressure.
  */
-static ssize_t __init setup_pcpu_embed(size_t static_size)
+static ssize_t __init setup_pcpu_embed(size_t static_size, bool chosen)
 {
        size_t reserve = PERCPU_MODULE_RESERVE + PERCPU_DYNAMIC_RESERVE;
 
@@ -258,7 +338,7 @@ static ssize_t __init setup_pcpu_embed(size_t static_size)
         * this.  Also, embedding allocation doesn't play well with
         * NUMA.
         */
-       if (!cpu_has_pse || pcpu_need_numa())
+       if (!chosen && (!cpu_has_pse || pcpu_need_numa()))
                return -EINVAL;
 
        return pcpu_embed_first_chunk(static_size, PERCPU_FIRST_CHUNK_RESERVE,
@@ -308,8 +388,11 @@ static ssize_t __init setup_pcpu_4k(size_t static_size)
                        void *ptr;
 
                        ptr = pcpu_alloc_bootmem(cpu, PAGE_SIZE, PAGE_SIZE);
-                       if (!ptr)
+                       if (!ptr) {
+                               pr_warning("PERCPU: failed to allocate "
+                                          "4k page for cpu%u\n", cpu);
                                goto enomem;
+                       }
 
                        memcpy(ptr, __per_cpu_load + i * PAGE_SIZE, PAGE_SIZE);
                        pcpu4k_pages[j++] = virt_to_page(ptr);
@@ -333,6 +416,16 @@ out_free_ar:
        return ret;
 }
 
+/* for explicit first chunk allocator selection */
+static char pcpu_chosen_alloc[16] __initdata;
+
+static int __init percpu_alloc_setup(char *str)
+{
+       strncpy(pcpu_chosen_alloc, str, sizeof(pcpu_chosen_alloc) - 1);
+       return 0;
+}
+early_param("percpu_alloc", percpu_alloc_setup);
+
 static inline void setup_percpu_segment(int cpu)
 {
 #ifdef CONFIG_X86_32
@@ -346,11 +439,6 @@ static inline void setup_percpu_segment(int cpu)
 #endif
 }
 
-/*
- * Great future plan:
- * Declare PDA itself and support (irqstack,tss,pgd) as per cpu data.
- * Always point %gs to its beginning
- */
 void __init setup_per_cpu_areas(void)
 {
        size_t static_size = __per_cpu_end - __per_cpu_start;
@@ -367,9 +455,26 @@ void __init setup_per_cpu_areas(void)
         * of large page mappings.  Please read comments on top of
         * each allocator for details.
         */
-       ret = setup_pcpu_remap(static_size);
-       if (ret < 0)
-               ret = setup_pcpu_embed(static_size);
+       ret = -EINVAL;
+       if (strlen(pcpu_chosen_alloc)) {
+               if (strcmp(pcpu_chosen_alloc, "4k")) {
+                       if (!strcmp(pcpu_chosen_alloc, "lpage"))
+                               ret = setup_pcpu_lpage(static_size, true);
+                       else if (!strcmp(pcpu_chosen_alloc, "embed"))
+                               ret = setup_pcpu_embed(static_size, true);
+                       else
+                               pr_warning("PERCPU: unknown allocator %s "
+                                          "specified\n", pcpu_chosen_alloc);
+                       if (ret < 0)
+                               pr_warning("PERCPU: %s allocator failed (%zd), "
+                                          "falling back to 4k\n",
+                                          pcpu_chosen_alloc, ret);
+               }
+       } else {
+               ret = setup_pcpu_lpage(static_size, false);
+               if (ret < 0)
+                       ret = setup_pcpu_embed(static_size, false);
+       }
        if (ret < 0)
                ret = setup_pcpu_4k(static_size);
        if (ret < 0)
index 124d40c..8ccabb8 100644 (file)
@@ -711,7 +711,6 @@ uv_activation_descriptor_init(int node, int pnode)
        unsigned long pa;
        unsigned long m;
        unsigned long n;
-       unsigned long mmr_image;
        struct bau_desc *adp;
        struct bau_desc *ad2;
 
@@ -727,12 +726,8 @@ uv_activation_descriptor_init(int node, int pnode)
        n = pa >> uv_nshift;
        m = pa & uv_mmask;
 
-       mmr_image = uv_read_global_mmr64(pnode, UVH_LB_BAU_SB_DESCRIPTOR_BASE);
-       if (mmr_image) {
-               uv_write_global_mmr64(pnode, (unsigned long)
-                                     UVH_LB_BAU_SB_DESCRIPTOR_BASE,
-                                     (n << UV_DESC_BASE_PNODE_SHIFT | m));
-       }
+       uv_write_global_mmr64(pnode, UVH_LB_BAU_SB_DESCRIPTOR_BASE,
+                             (n << UV_DESC_BASE_PNODE_SHIFT | m));
 
        /*
         * initializing all 8 (UV_ITEMS_PER_DESCRIPTOR) descriptors for each
index a0f48f5..5204332 100644 (file)
@@ -346,6 +346,9 @@ io_check_error(unsigned char reason, struct pt_regs *regs)
        printk(KERN_EMERG "NMI: IOCK error (debug interrupt?)\n");
        show_registers(regs);
 
+       if (panic_on_io_nmi)
+               panic("NMI IOCK error: Not continuing");
+
        /* Re-enable the IOCK line, wait for a few seconds */
        reason = (reason & 0xf) | 8;
        outb(reason, 0x61);
index 5c3d6e8..7030b5f 100644 (file)
@@ -2157,7 +2157,7 @@ static void reset_rsvds_bits_mask(struct kvm_vcpu *vcpu, int level)
                else
                        /* 32 bits PSE 4MB page */
                        context->rsvd_bits_mask[1][1] = rsvd_bits(13, 21);
-               context->rsvd_bits_mask[1][0] = ~0ull;
+               context->rsvd_bits_mask[1][0] = context->rsvd_bits_mask[1][0];
                break;
        case PT32E_ROOT_LEVEL:
                context->rsvd_bits_mask[0][2] =
@@ -2170,7 +2170,7 @@ static void reset_rsvds_bits_mask(struct kvm_vcpu *vcpu, int level)
                context->rsvd_bits_mask[1][1] = exb_bit_rsvd |
                        rsvd_bits(maxphyaddr, 62) |
                        rsvd_bits(13, 20);              /* large page */
-               context->rsvd_bits_mask[1][0] = ~0ull;
+               context->rsvd_bits_mask[1][0] = context->rsvd_bits_mask[1][0];
                break;
        case PT64_ROOT_LEVEL:
                context->rsvd_bits_mask[0][3] = exb_bit_rsvd |
@@ -2186,7 +2186,7 @@ static void reset_rsvds_bits_mask(struct kvm_vcpu *vcpu, int level)
                context->rsvd_bits_mask[1][1] = exb_bit_rsvd |
                        rsvd_bits(maxphyaddr, 51) |
                        rsvd_bits(13, 20);              /* large page */
-               context->rsvd_bits_mask[1][0] = ~0ull;
+               context->rsvd_bits_mask[1][0] = context->rsvd_bits_mask[1][0];
                break;
        }
 }
index 258e459..67785f6 100644 (file)
@@ -281,7 +281,7 @@ static u64 *FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr,
 {
        unsigned access = gw->pt_access;
        struct kvm_mmu_page *shadow_page;
-       u64 spte, *sptep;
+       u64 spte, *sptep = NULL;
        int direct;
        gfn_t table_gfn;
        int r;
index e770bf3..356a0ce 100644 (file)
@@ -3012,6 +3012,12 @@ static int handle_vmcall(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
        return 1;
 }
 
+static int handle_vmx_insn(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+{
+       kvm_queue_exception(vcpu, UD_VECTOR);
+       return 1;
+}
+
 static int handle_invlpg(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
 {
        unsigned long exit_qualification = vmcs_readl(EXIT_QUALIFICATION);
@@ -3198,6 +3204,15 @@ static int (*kvm_vmx_exit_handlers[])(struct kvm_vcpu *vcpu,
        [EXIT_REASON_HLT]                     = handle_halt,
        [EXIT_REASON_INVLPG]                  = handle_invlpg,
        [EXIT_REASON_VMCALL]                  = handle_vmcall,
+       [EXIT_REASON_VMCLEAR]                 = handle_vmx_insn,
+       [EXIT_REASON_VMLAUNCH]                = handle_vmx_insn,
+       [EXIT_REASON_VMPTRLD]                 = handle_vmx_insn,
+       [EXIT_REASON_VMPTRST]                 = handle_vmx_insn,
+       [EXIT_REASON_VMREAD]                  = handle_vmx_insn,
+       [EXIT_REASON_VMRESUME]                = handle_vmx_insn,
+       [EXIT_REASON_VMWRITE]                 = handle_vmx_insn,
+       [EXIT_REASON_VMOFF]                   = handle_vmx_insn,
+       [EXIT_REASON_VMON]                    = handle_vmx_insn,
        [EXIT_REASON_TPR_BELOW_THRESHOLD]     = handle_tpr_below_threshold,
        [EXIT_REASON_APIC_ACCESS]             = handle_apic_access,
        [EXIT_REASON_WBINVD]                  = handle_wbinvd,
index 249540f..fe5474a 100644 (file)
@@ -898,6 +898,7 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata)
        case MSR_VM_HSAVE_PA:
        case MSR_P6_EVNTSEL0:
        case MSR_P6_EVNTSEL1:
+       case MSR_K7_EVNTSEL0:
                data = 0;
                break;
        case MSR_MTRRcap:
index c1b6c23..616de46 100644 (file)
@@ -1361,7 +1361,7 @@ static inline int writeback(struct x86_emulate_ctxt *ctxt,
        return 0;
 }
 
-void toggle_interruptibility(struct x86_emulate_ctxt *ctxt, u32 mask)
+static void toggle_interruptibility(struct x86_emulate_ctxt *ctxt, u32 mask)
 {
        u32 int_shadow = kvm_x86_ops->get_interrupt_shadow(ctxt->vcpu, mask);
        /*
index f456860..ff485d3 100644 (file)
@@ -55,8 +55,10 @@ static void delay_tsc(unsigned long loops)
 
        preempt_disable();
        cpu = smp_processor_id();
+       rdtsc_barrier();
        rdtscl(bclock);
        for (;;) {
+               rdtsc_barrier();
                rdtscl(now);
                if ((now - bclock) >= loops)
                        break;
@@ -78,6 +80,7 @@ static void delay_tsc(unsigned long loops)
                if (unlikely(cpu != smp_processor_id())) {
                        loops -= (now - bclock);
                        cpu = smp_processor_id();
+                       rdtsc_barrier();
                        rdtscl(bclock);
                }
        }
index f53b57e..47ce9a2 100644 (file)
@@ -177,20 +177,6 @@ static int __meminit save_mr(struct map_range *mr, int nr_range,
        return nr_range;
 }
 
-#ifdef CONFIG_X86_64
-static void __init init_gbpages(void)
-{
-       if (direct_gbpages && cpu_has_gbpages)
-               printk(KERN_INFO "Using GB pages for direct mapping\n");
-       else
-               direct_gbpages = 0;
-}
-#else
-static inline void init_gbpages(void)
-{
-}
-#endif
-
 /*
  * Setup the direct mapping of the physical memory at PAGE_OFFSET.
  * This runs before bootmem is initialized and gets pages directly from
@@ -210,9 +196,6 @@ unsigned long __init_refok init_memory_mapping(unsigned long start,
 
        printk(KERN_INFO "init_memory_mapping: %016lx-%016lx\n", start, end);
 
-       if (!after_bootmem)
-               init_gbpages();
-
 #if defined(CONFIG_DEBUG_PAGEALLOC) || defined(CONFIG_KMEMCHECK)
        /*
         * For CONFIG_DEBUG_PAGEALLOC, identity mapping will use small pages.
index c4378f4..b177652 100644 (file)
@@ -598,6 +598,8 @@ void __init paging_init(void)
 
        sparse_memory_present_with_active_regions(MAX_NUMNODES);
        sparse_init();
+       /* clear the default setting with node 0 */
+       nodes_clear(node_states[N_NORMAL_MEMORY]);
        free_area_init_nodes(max_zone_pfns);
 }
 
index 3cfe9ce..1b734d7 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/interrupt.h>
 #include <linux/seq_file.h>
 #include <linux/debugfs.h>
+#include <linux/pfn.h>
 
 #include <asm/e820.h>
 #include <asm/processor.h>
@@ -681,8 +682,9 @@ static int __change_page_attr_set_clr(struct cpa_data *cpa, int checkalias);
 static int cpa_process_alias(struct cpa_data *cpa)
 {
        struct cpa_data alias_cpa;
-       int ret = 0;
-       unsigned long temp_cpa_vaddr, vaddr;
+       unsigned long laddr = (unsigned long)__va(cpa->pfn << PAGE_SHIFT);
+       unsigned long vaddr, remapped;
+       int ret;
 
        if (cpa->pfn >= max_pfn_mapped)
                return 0;
@@ -706,42 +708,55 @@ static int cpa_process_alias(struct cpa_data *cpa)
                    PAGE_OFFSET + (max_pfn_mapped << PAGE_SHIFT)))) {
 
                alias_cpa = *cpa;
-               temp_cpa_vaddr = (unsigned long) __va(cpa->pfn << PAGE_SHIFT);
-               alias_cpa.vaddr = &temp_cpa_vaddr;
+               alias_cpa.vaddr = &laddr;
                alias_cpa.flags &= ~(CPA_PAGES_ARRAY | CPA_ARRAY);
 
-
                ret = __change_page_attr_set_clr(&alias_cpa, 0);
+               if (ret)
+                       return ret;
        }
 
 #ifdef CONFIG_X86_64
-       if (ret)
-               return ret;
        /*
-        * No need to redo, when the primary call touched the high
-        * mapping already:
-        */
-       if (within(vaddr, (unsigned long) _text, _brk_end))
-               return 0;
-
-       /*
-        * If the physical address is inside the kernel map, we need
+        * If the primary call didn't touch the high mapping already
+        * and the physical address is inside the kernel map, we need
         * to touch the high mapped kernel as well:
         */
-       if (!within(cpa->pfn, highmap_start_pfn(), highmap_end_pfn()))
-               return 0;
+       if (!within(vaddr, (unsigned long)_text, _brk_end) &&
+           within(cpa->pfn, highmap_start_pfn(), highmap_end_pfn())) {
+               unsigned long temp_cpa_vaddr = (cpa->pfn << PAGE_SHIFT) +
+                                              __START_KERNEL_map - phys_base;
+               alias_cpa = *cpa;
+               alias_cpa.vaddr = &temp_cpa_vaddr;
+               alias_cpa.flags &= ~(CPA_PAGES_ARRAY | CPA_ARRAY);
 
-       alias_cpa = *cpa;
-       temp_cpa_vaddr = (cpa->pfn << PAGE_SHIFT) + __START_KERNEL_map - phys_base;
-       alias_cpa.vaddr = &temp_cpa_vaddr;
-       alias_cpa.flags &= ~(CPA_PAGES_ARRAY | CPA_ARRAY);
+               /*
+                * The high mapping range is imprecise, so ignore the
+                * return value.
+                */
+               __change_page_attr_set_clr(&alias_cpa, 0);
+       }
+#endif
 
        /*
-        * The high mapping range is imprecise, so ignore the return value.
+        * If the PMD page was partially used for per-cpu remapping,
+        * the recycled area needs to be split and modified.  Because
+        * the area is always proper subset of a PMD page
+        * cpa->numpages is guaranteed to be 1 for these areas, so
+        * there's no need to loop over and check for further remaps.
         */
-       __change_page_attr_set_clr(&alias_cpa, 0);
-#endif
-       return ret;
+       remapped = (unsigned long)pcpu_lpage_remapped((void *)laddr);
+       if (remapped) {
+               WARN_ON(cpa->numpages > 1);
+               alias_cpa = *cpa;
+               alias_cpa.vaddr = &remapped;
+               alias_cpa.flags &= ~(CPA_PAGES_ARRAY | CPA_ARRAY);
+               ret = __change_page_attr_set_clr(&alias_cpa, 0);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
 }
 
 static int __change_page_attr_set_clr(struct cpa_data *cpa, int checkalias)
index d277ef1..b3d20b9 100644 (file)
@@ -244,7 +244,7 @@ static void __restore_processor_state(struct saved_context *ctxt)
        do_fpu_end();
        mtrr_ap_init();
 
-#ifdef CONFIG_X86_32
+#ifdef CONFIG_X86_OLD_MCE
        mcheck_init(&boot_cpu_data);
 #endif
 }
index edad415..2f0b86b 100644 (file)
@@ -545,7 +545,7 @@ static int iss_net_start_xmit(struct sk_buff *skb, struct net_device *dev)
        spin_unlock_irqrestore(&lp->lock, flags);
 
        dev_kfree_skb(skb);
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 
index e9fa4dd..6c54ed0 100644 (file)
@@ -5,7 +5,7 @@
 obj-$(CONFIG_BLOCK) := elevator.o blk-core.o blk-tag.o blk-sysfs.o \
                        blk-barrier.o blk-settings.o blk-ioc.o blk-map.o \
                        blk-exec.o blk-merge.o blk-softirq.o blk-timeout.o \
-                       ioctl.o genhd.o scsi_ioctl.o cmd-filter.o
+                       ioctl.o genhd.o scsi_ioctl.o
 
 obj-$(CONFIG_BLK_DEV_BSG)      += bsg.o
 obj-$(CONFIG_IOSCHED_NOOP)     += noop-iosched.o
index b06cf5c..4b45435 100644 (file)
@@ -595,8 +595,6 @@ blk_init_queue_node(request_fn_proc *rfn, spinlock_t *lock, int node_id)
 
        q->sg_reserved_size = INT_MAX;
 
-       blk_set_cmd_filter_defaults(&q->cmd_filter);
-
        /*
         * all done
         */
@@ -1172,6 +1170,11 @@ static int __make_request(struct request_queue *q, struct bio *bio)
        const int unplug = bio_unplug(bio);
        int rw_flags;
 
+       if (bio_barrier(bio) && bio_has_data(bio) &&
+           (q->next_ordered == QUEUE_ORDERED_NONE)) {
+               bio_endio(bio, -EOPNOTSUPP);
+               return 0;
+       }
        /*
         * low level driver can indicate that it wants pages above a
         * certain limit bounced to low memory (ie for highmem, or even
@@ -1472,11 +1475,6 @@ static inline void __generic_make_request(struct bio *bio)
                        err = -EOPNOTSUPP;
                        goto end_io;
                }
-               if (bio_barrier(bio) && bio_has_data(bio) &&
-                   (q->next_ordered == QUEUE_ORDERED_NONE)) {
-                       err = -EOPNOTSUPP;
-                       goto end_io;
-               }
 
                ret = q->make_request_fn(q, bio);
        } while (ret);
@@ -2365,7 +2363,7 @@ int blk_rq_prep_clone(struct request *rq, struct request *rq_src,
                __bio_clone(bio, bio_src);
 
                if (bio_integrity(bio_src) &&
-                   bio_integrity_clone(bio, bio_src, gfp_mask))
+                   bio_integrity_clone(bio, bio_src, gfp_mask, bs))
                        goto free_and_out;
 
                if (bio_ctr && bio_ctr(bio, bio_src, data))
index 39ce644..e199967 100644 (file)
@@ -350,6 +350,12 @@ static int attempt_merge(struct request_queue *q, struct request *req,
        if (blk_integrity_rq(req) != blk_integrity_rq(next))
                return 0;
 
+       /* don't merge requests of different failfast settings */
+       if (blk_failfast_dev(req)       != blk_failfast_dev(next)       ||
+           blk_failfast_transport(req) != blk_failfast_transport(next) ||
+           blk_failfast_driver(req)    != blk_failfast_driver(next))
+               return 0;
+
        /*
         * If we are allowed to merge, then append bio list
         * from next to rq and release next. merge_requests_fn
index e7d4752..5f184bb 100644 (file)
@@ -186,7 +186,7 @@ static int blk_fill_sgv4_hdr_rq(struct request_queue *q, struct request *rq,
                return -EFAULT;
 
        if (hdr->subprotocol == BSG_SUB_PROTOCOL_SCSI_CMD) {
-               if (blk_verify_command(&q->cmd_filter, rq->cmd, has_write_perm))
+               if (blk_verify_command(rq->cmd, has_write_perm))
                        return -EPERM;
        } else if (!capable(CAP_SYS_RAWIO))
                return -EPERM;
index 833ec18..87276eb 100644 (file)
@@ -71,6 +71,51 @@ struct cfq_rb_root {
 #define CFQ_RB_ROOT    (struct cfq_rb_root) { RB_ROOT, NULL, }
 
 /*
+ * Per process-grouping structure
+ */
+struct cfq_queue {
+       /* reference count */
+       atomic_t ref;
+       /* various state flags, see below */
+       unsigned int flags;
+       /* parent cfq_data */
+       struct cfq_data *cfqd;
+       /* service_tree member */
+       struct rb_node rb_node;
+       /* service_tree key */
+       unsigned long rb_key;
+       /* prio tree member */
+       struct rb_node p_node;
+       /* prio tree root we belong to, if any */
+       struct rb_root *p_root;
+       /* sorted list of pending requests */
+       struct rb_root sort_list;
+       /* if fifo isn't expired, next request to serve */
+       struct request *next_rq;
+       /* requests queued in sort_list */
+       int queued[2];
+       /* currently allocated requests */
+       int allocated[2];
+       /* fifo list of requests in sort_list */
+       struct list_head fifo;
+
+       unsigned long slice_end;
+       long slice_resid;
+       unsigned int slice_dispatch;
+
+       /* pending metadata requests */
+       int meta_pending;
+       /* number of requests that are on the dispatch list or inside driver */
+       int dispatched;
+
+       /* io prio of this group */
+       unsigned short ioprio, org_ioprio;
+       unsigned short ioprio_class, org_ioprio_class;
+
+       pid_t pid;
+};
+
+/*
  * Per block device queue structure
  */
 struct cfq_data {
@@ -135,51 +180,11 @@ struct cfq_data {
        unsigned int cfq_slice_idle;
 
        struct list_head cic_list;
-};
-
-/*
- * Per process-grouping structure
- */
-struct cfq_queue {
-       /* reference count */
-       atomic_t ref;
-       /* various state flags, see below */
-       unsigned int flags;
-       /* parent cfq_data */
-       struct cfq_data *cfqd;
-       /* service_tree member */
-       struct rb_node rb_node;
-       /* service_tree key */
-       unsigned long rb_key;
-       /* prio tree member */
-       struct rb_node p_node;
-       /* prio tree root we belong to, if any */
-       struct rb_root *p_root;
-       /* sorted list of pending requests */
-       struct rb_root sort_list;
-       /* if fifo isn't expired, next request to serve */
-       struct request *next_rq;
-       /* requests queued in sort_list */
-       int queued[2];
-       /* currently allocated requests */
-       int allocated[2];
-       /* fifo list of requests in sort_list */
-       struct list_head fifo;
 
-       unsigned long slice_end;
-       long slice_resid;
-       unsigned int slice_dispatch;
-
-       /* pending metadata requests */
-       int meta_pending;
-       /* number of requests that are on the dispatch list or inside driver */
-       int dispatched;
-
-       /* io prio of this group */
-       unsigned short ioprio, org_ioprio;
-       unsigned short ioprio_class, org_ioprio_class;
-
-       pid_t pid;
+       /*
+        * Fallback dummy cfqq for extreme OOM conditions
+        */
+       struct cfq_queue oom_cfqq;
 };
 
 enum cfqq_state_flags {
@@ -1641,6 +1646,26 @@ static void cfq_ioc_set_ioprio(struct io_context *ioc)
        ioc->ioprio_changed = 0;
 }
 
+static void cfq_init_cfqq(struct cfq_data *cfqd, struct cfq_queue *cfqq,
+                         pid_t pid, int is_sync)
+{
+       RB_CLEAR_NODE(&cfqq->rb_node);
+       RB_CLEAR_NODE(&cfqq->p_node);
+       INIT_LIST_HEAD(&cfqq->fifo);
+
+       atomic_set(&cfqq->ref, 0);
+       cfqq->cfqd = cfqd;
+
+       cfq_mark_cfqq_prio_changed(cfqq);
+
+       if (is_sync) {
+               if (!cfq_class_idle(cfqq))
+                       cfq_mark_cfqq_idle_window(cfqq);
+               cfq_mark_cfqq_sync(cfqq);
+       }
+       cfqq->pid = pid;
+}
+
 static struct cfq_queue *
 cfq_find_alloc_queue(struct cfq_data *cfqd, int is_sync,
                     struct io_context *ioc, gfp_t gfp_mask)
@@ -1653,56 +1678,40 @@ retry:
        /* cic always exists here */
        cfqq = cic_to_cfqq(cic, is_sync);
 
-       if (!cfqq) {
+       /*
+        * Always try a new alloc if we fell back to the OOM cfqq
+        * originally, since it should just be a temporary situation.
+        */
+       if (!cfqq || cfqq == &cfqd->oom_cfqq) {
+               cfqq = NULL;
                if (new_cfqq) {
                        cfqq = new_cfqq;
                        new_cfqq = NULL;
                } else if (gfp_mask & __GFP_WAIT) {
-                       /*
-                        * Inform the allocator of the fact that we will
-                        * just repeat this allocation if it fails, to allow
-                        * the allocator to do whatever it needs to attempt to
-                        * free memory.
-                        */
                        spin_unlock_irq(cfqd->queue->queue_lock);
                        new_cfqq = kmem_cache_alloc_node(cfq_pool,
-                                       gfp_mask | __GFP_NOFAIL | __GFP_ZERO,
+                                       gfp_mask | __GFP_ZERO,
                                        cfqd->queue->node);
                        spin_lock_irq(cfqd->queue->queue_lock);
-                       goto retry;
+                       if (new_cfqq)
+                               goto retry;
                } else {
                        cfqq = kmem_cache_alloc_node(cfq_pool,
                                        gfp_mask | __GFP_ZERO,
                                        cfqd->queue->node);
-                       if (!cfqq)
-                               goto out;
                }
 
-               RB_CLEAR_NODE(&cfqq->rb_node);
-               RB_CLEAR_NODE(&cfqq->p_node);
-               INIT_LIST_HEAD(&cfqq->fifo);
-
-               atomic_set(&cfqq->ref, 0);
-               cfqq->cfqd = cfqd;
-
-               cfq_mark_cfqq_prio_changed(cfqq);
-
-               cfq_init_prio_data(cfqq, ioc);
-
-               if (is_sync) {
-                       if (!cfq_class_idle(cfqq))
-                               cfq_mark_cfqq_idle_window(cfqq);
-                       cfq_mark_cfqq_sync(cfqq);
-               }
-               cfqq->pid = current->pid;
-               cfq_log_cfqq(cfqd, cfqq, "alloced");
+               if (cfqq) {
+                       cfq_init_cfqq(cfqd, cfqq, current->pid, is_sync);
+                       cfq_init_prio_data(cfqq, ioc);
+                       cfq_log_cfqq(cfqd, cfqq, "alloced");
+               } else
+                       cfqq = &cfqd->oom_cfqq;
        }
 
        if (new_cfqq)
                kmem_cache_free(cfq_pool, new_cfqq);
 
-out:
-       WARN_ON((gfp_mask & __GFP_WAIT) && !cfqq);
        return cfqq;
 }
 
@@ -1735,11 +1744,8 @@ cfq_get_queue(struct cfq_data *cfqd, int is_sync, struct io_context *ioc,
                cfqq = *async_cfqq;
        }
 
-       if (!cfqq) {
+       if (!cfqq)
                cfqq = cfq_find_alloc_queue(cfqd, is_sync, ioc, gfp_mask);
-               if (!cfqq)
-                       return NULL;
-       }
 
        /*
         * pin the queue now that it's allocated, scheduler exit will prune it
@@ -2307,10 +2313,6 @@ cfq_set_request(struct request_queue *q, struct request *rq, gfp_t gfp_mask)
        cfqq = cic_to_cfqq(cic, is_sync);
        if (!cfqq) {
                cfqq = cfq_get_queue(cfqd, is_sync, cic->ioc, gfp_mask);
-
-               if (!cfqq)
-                       goto queue_fail;
-
                cic_set_cfqq(cic, cfqq, is_sync);
        }
 
@@ -2465,6 +2467,14 @@ static void *cfq_init_queue(struct request_queue *q)
        for (i = 0; i < CFQ_PRIO_LISTS; i++)
                cfqd->prio_trees[i] = RB_ROOT;
 
+       /*
+        * Our fallback cfqq if cfq_find_alloc_queue() runs into OOM issues.
+        * Grab a permanent reference to it, so that the normal code flow
+        * will not attempt to free it.
+        */
+       cfq_init_cfqq(cfqd, &cfqd->oom_cfqq, 1, 0);
+       atomic_inc(&cfqd->oom_cfqq.ref);
+
        INIT_LIST_HEAD(&cfqd->cic_list);
 
        cfqd->queue = q;
diff --git a/block/cmd-filter.c b/block/cmd-filter.c
deleted file mode 100644 (file)
index 572bbc2..0000000
+++ /dev/null
@@ -1,233 +0,0 @@
-/*
- * Copyright 2004 Peter M. Jones <pjones@redhat.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 Licens
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-
- *
- */
-
-#include <linux/list.h>
-#include <linux/genhd.h>
-#include <linux/spinlock.h>
-#include <linux/capability.h>
-#include <linux/bitops.h>
-#include <linux/blkdev.h>
-
-#include <scsi/scsi.h>
-#include <linux/cdrom.h>
-
-int blk_verify_command(struct blk_cmd_filter *filter,
-                      unsigned char *cmd, fmode_t has_write_perm)
-{
-       /* root can do any command. */
-       if (capable(CAP_SYS_RAWIO))
-               return 0;
-
-       /* if there's no filter set, assume we're filtering everything out */
-       if (!filter)
-               return -EPERM;
-
-       /* Anybody who can open the device can do a read-safe command */
-       if (test_bit(cmd[0], filter->read_ok))
-               return 0;
-
-       /* Write-safe commands require a writable open */
-       if (test_bit(cmd[0], filter->write_ok) && has_write_perm)
-               return 0;
-
-       return -EPERM;
-}
-EXPORT_SYMBOL(blk_verify_command);
-
-#if 0
-/* and now, the sysfs stuff */
-static ssize_t rcf_cmds_show(struct blk_cmd_filter *filter, char *page,
-                            int rw)
-{
-       char *npage = page;
-       unsigned long *okbits;
-       int i;
-
-       if (rw == READ)
-               okbits = filter->read_ok;
-       else
-               okbits = filter->write_ok;
-
-       for (i = 0; i < BLK_SCSI_MAX_CMDS; i++) {
-               if (test_bit(i, okbits)) {
-                       npage += sprintf(npage, "0x%02x", i);
-                       if (i < BLK_SCSI_MAX_CMDS - 1)
-                               sprintf(npage++, " ");
-               }
-       }
-
-       if (npage != page)
-               npage += sprintf(npage, "\n");
-
-       return npage - page;
-}
-
-static ssize_t rcf_readcmds_show(struct blk_cmd_filter *filter, char *page)
-{
-       return rcf_cmds_show(filter, page, READ);
-}
-
-static ssize_t rcf_writecmds_show(struct blk_cmd_filter *filter,
-                                char *page)
-{
-       return rcf_cmds_show(filter, page, WRITE);
-}
-
-static ssize_t rcf_cmds_store(struct blk_cmd_filter *filter,
-                             const char *page, size_t count, int rw)
-{
-       unsigned long okbits[BLK_SCSI_CMD_PER_LONG], *target_okbits;
-       int cmd, set;
-       char *p, *status;
-
-       if (rw == READ) {
-               memcpy(&okbits, filter->read_ok, sizeof(okbits));
-               target_okbits = filter->read_ok;
-       } else {
-               memcpy(&okbits, filter->write_ok, sizeof(okbits));
-               target_okbits = filter->write_ok;
-       }
-
-       while ((p = strsep((char **)&page, " ")) != NULL) {
-               set = 1;
-
-               if (p[0] == '+') {
-                       p++;
-               } else if (p[0] == '-') {
-                       set = 0;
-                       p++;
-               }
-
-               cmd = simple_strtol(p, &status, 16);
-
-               /* either of these cases means invalid input, so do nothing. */
-               if ((status == p) || cmd >= BLK_SCSI_MAX_CMDS)
-                       return -EINVAL;
-
-               if (set)
-                       __set_bit(cmd, okbits);
-               else
-                       __clear_bit(cmd, okbits);
-       }
-
-       memcpy(target_okbits, okbits, sizeof(okbits));
-       return count;
-}
-
-static ssize_t rcf_readcmds_store(struct blk_cmd_filter *filter,
-                                 const char *page, size_t count)
-{
-       return rcf_cmds_store(filter, page, count, READ);
-}
-
-static ssize_t rcf_writecmds_store(struct blk_cmd_filter *filter,
-                                  const char *page, size_t count)
-{
-       return rcf_cmds_store(filter, page, count, WRITE);
-}
-
-struct rcf_sysfs_entry {
-       struct attribute attr;
-       ssize_t (*show)(struct blk_cmd_filter *, char *);
-       ssize_t (*store)(struct blk_cmd_filter *, const char *, size_t);
-};
-
-static struct rcf_sysfs_entry rcf_readcmds_entry = {
-       .attr = { .name = "read_table", .mode = S_IRUGO | S_IWUSR },
-       .show = rcf_readcmds_show,
-       .store = rcf_readcmds_store,
-};
-
-static struct rcf_sysfs_entry rcf_writecmds_entry = {
-       .attr = {.name = "write_table", .mode = S_IRUGO | S_IWUSR },
-       .show = rcf_writecmds_show,
-       .store = rcf_writecmds_store,
-};
-
-static struct attribute *default_attrs[] = {
-       &rcf_readcmds_entry.attr,
-       &rcf_writecmds_entry.attr,
-       NULL,
-};
-
-#define to_rcf(atr) container_of((atr), struct rcf_sysfs_entry, attr)
-
-static ssize_t
-rcf_attr_show(struct kobject *kobj, struct attribute *attr, char *page)
-{
-       struct rcf_sysfs_entry *entry = to_rcf(attr);
-       struct blk_cmd_filter *filter;
-
-       filter = container_of(kobj, struct blk_cmd_filter, kobj);
-       if (entry->show)
-               return entry->show(filter, page);
-
-       return 0;
-}
-
-static ssize_t
-rcf_attr_store(struct kobject *kobj, struct attribute *attr,
-                       const char *page, size_t length)
-{
-       struct rcf_sysfs_entry *entry = to_rcf(attr);
-       struct blk_cmd_filter *filter;
-
-       if (!capable(CAP_SYS_RAWIO))
-               return -EPERM;
-
-       if (!entry->store)
-               return -EINVAL;
-
-       filter = container_of(kobj, struct blk_cmd_filter, kobj);
-       return entry->store(filter, page, length);
-}
-
-static struct sysfs_ops rcf_sysfs_ops = {
-       .show = rcf_attr_show,
-       .store = rcf_attr_store,
-};
-
-static struct kobj_type rcf_ktype = {
-       .sysfs_ops = &rcf_sysfs_ops,
-       .default_attrs = default_attrs,
-};
-
-int blk_register_filter(struct gendisk *disk)
-{
-       int ret;
-       struct blk_cmd_filter *filter = &disk->queue->cmd_filter;
-
-       ret = kobject_init_and_add(&filter->kobj, &rcf_ktype,
-                                  &disk_to_dev(disk)->kobj,
-                                  "%s", "cmd_filter");
-       if (ret < 0)
-               return ret;
-
-       return 0;
-}
-EXPORT_SYMBOL(blk_register_filter);
-
-void blk_unregister_filter(struct gendisk *disk)
-{
-       struct blk_cmd_filter *filter = &disk->queue->cmd_filter;
-
-       kobject_put(&filter->kobj);
-}
-EXPORT_SYMBOL(blk_unregister_filter);
-#endif
index ca86192..6f23753 100644 (file)
@@ -100,6 +100,14 @@ int elv_rq_merge_ok(struct request *rq, struct bio *bio)
        if (bio_integrity(bio) != blk_integrity_rq(rq))
                return 0;
 
+       /*
+        * Don't merge if failfast settings don't match
+        */
+       if (bio_failfast_dev(bio)       != blk_failfast_dev(rq)         ||
+           bio_failfast_transport(bio) != blk_failfast_transport(rq)   ||
+           bio_failfast_driver(bio)    != blk_failfast_driver(rq))
+               return 0;
+
        if (!elv_iosched_allow_merge(rq, bio))
                return 0;
 
index 5f8e798..f0e0ce0 100644 (file)
 #include <scsi/scsi_ioctl.h>
 #include <scsi/scsi_cmnd.h>
 
+struct blk_cmd_filter {
+       unsigned long read_ok[BLK_SCSI_CMD_PER_LONG];
+       unsigned long write_ok[BLK_SCSI_CMD_PER_LONG];
+} blk_default_cmd_filter;
+
 /* Command group 3 is reserved and should never be used.  */
 const unsigned char scsi_command_size_tbl[8] =
 {
@@ -105,7 +110,7 @@ static int sg_emulated_host(struct request_queue *q, int __user *p)
        return put_user(1, p);
 }
 
-void blk_set_cmd_filter_defaults(struct blk_cmd_filter *filter)
+static void blk_set_cmd_filter_defaults(struct blk_cmd_filter *filter)
 {
        /* Basic read-only commands */
        __set_bit(TEST_UNIT_READY, filter->read_ok);
@@ -187,14 +192,37 @@ void blk_set_cmd_filter_defaults(struct blk_cmd_filter *filter)
        __set_bit(GPCMD_SET_STREAMING, filter->write_ok);
        __set_bit(GPCMD_SET_READ_AHEAD, filter->write_ok);
 }
-EXPORT_SYMBOL_GPL(blk_set_cmd_filter_defaults);
+
+int blk_verify_command(unsigned char *cmd, fmode_t has_write_perm)
+{
+       struct blk_cmd_filter *filter = &blk_default_cmd_filter;
+
+       /* root can do any command. */
+       if (capable(CAP_SYS_RAWIO))
+               return 0;
+
+       /* if there's no filter set, assume we're filtering everything out */
+       if (!filter)
+               return -EPERM;
+
+       /* Anybody who can open the device can do a read-safe command */
+       if (test_bit(cmd[0], filter->read_ok))
+               return 0;
+
+       /* Write-safe commands require a writable open */
+       if (test_bit(cmd[0], filter->write_ok) && has_write_perm)
+               return 0;
+
+       return -EPERM;
+}
+EXPORT_SYMBOL(blk_verify_command);
 
 static int blk_fill_sghdr_rq(struct request_queue *q, struct request *rq,
                             struct sg_io_hdr *hdr, fmode_t mode)
 {
        if (copy_from_user(rq->cmd, hdr->cmdp, hdr->cmd_len))
                return -EFAULT;
-       if (blk_verify_command(&q->cmd_filter, rq->cmd, mode & FMODE_WRITE))
+       if (blk_verify_command(rq->cmd, mode & FMODE_WRITE))
                return -EPERM;
 
        /*
@@ -427,7 +455,7 @@ int sg_scsi_ioctl(struct request_queue *q, struct gendisk *disk, fmode_t mode,
        if (in_len && copy_from_user(buffer, sic->data + cmdlen, in_len))
                goto error;
 
-       err = blk_verify_command(&q->cmd_filter, rq->cmd, mode & FMODE_WRITE);
+       err = blk_verify_command(rq->cmd, mode & FMODE_WRITE);
        if (err)
                goto error;
 
@@ -645,5 +673,10 @@ int scsi_cmd_ioctl(struct request_queue *q, struct gendisk *bd_disk, fmode_t mod
        blk_put_queue(q);
        return err;
 }
-
 EXPORT_SYMBOL(scsi_cmd_ioctl);
+
+int __init blk_scsi_ioctl_init(void)
+{
+       blk_set_cmd_filter_defaults(&blk_default_cmd_filter);
+       return 0;
+}
index 8a5bf3b..55b5b90 100644 (file)
@@ -395,7 +395,7 @@ struct pci_dev *acpi_get_pci_dev(acpi_handle handle)
                fn  = adr & 0xffff;
 
                pdev = pci_get_slot(pbus, PCI_DEVFN(dev, fn));
-               if (hnd == handle)
+               if (!pdev || hnd == handle)
                        break;
 
                pbus = pdev->subordinate;
index c7a527c..65a0655 100644 (file)
@@ -226,8 +226,18 @@ static inline void addQ(struct hlist_head *list, CommandList_struct *c)
 
 static inline void removeQ(CommandList_struct *c)
 {
-       if (WARN_ON(hlist_unhashed(&c->list)))
+       /*
+        * After kexec/dump some commands might still
+        * be in flight, which the firmware will try
+        * to complete. Resetting the firmware doesn't work
+        * with old fw revisions, so we have to mark
+        * them off as 'stale' to prevent the driver from
+        * falling over.
+        */
+       if (WARN_ON(hlist_unhashed(&c->list))) {
+               c->cmd_type = CMD_MSG_STALE;
                return;
+       }
 
        hlist_del_init(&c->list);
 }
@@ -4246,7 +4256,8 @@ static void fail_all_cmds(unsigned long ctlr)
        while (!hlist_empty(&h->cmpQ)) {
                c = hlist_entry(h->cmpQ.first, CommandList_struct, list);
                removeQ(c);
-               c->err_info->CommandStatus = CMD_HARDWARE_ERR;
+               if (c->cmd_type != CMD_MSG_STALE)
+                       c->err_info->CommandStatus = CMD_HARDWARE_ERR;
                if (c->cmd_type == CMD_RWREQ) {
                        complete_command(h, c, 0);
                } else if (c->cmd_type == CMD_IOCTL_PEND)
index cd665b0..dbaed1e 100644 (file)
@@ -274,6 +274,7 @@ typedef struct _ErrorInfo_struct {
 #define CMD_SCSI       0x03
 #define CMD_MSG_DONE   0x04
 #define CMD_MSG_TIMEOUT 0x05
+#define CMD_MSG_STALE  0xff
 
 /* This structure needs to be divisible by 8 for new
  * indexing method.
index 862b40c..91b7530 100644 (file)
@@ -3327,7 +3327,10 @@ static inline int set_geometry(unsigned int cmd, struct floppy_struct *g,
                if (!capable(CAP_SYS_ADMIN))
                        return -EPERM;
                mutex_lock(&open_lock);
-               LOCK_FDC(drive, 1);
+               if (lock_fdc(drive, 1)) {
+                       mutex_unlock(&open_lock);
+                       return -EINTR;
+               }
                floppy_type[type] = *g;
                floppy_type[type].name = "user format";
                for (cnt = type << 2; cnt < (type << 2) + 4; cnt++)
index 0bd01f4..6a06913 100644 (file)
@@ -1029,10 +1029,6 @@ config CS5535_GPIO
 
          If compiled as a module, it will be called cs5535_gpio.
 
-config GPIO_VR41XX
-       tristate "NEC VR4100 series General-purpose I/O Unit support"
-       depends on CPU_VR41XX
-
 config RAW_DRIVER
        tristate "RAW driver (/dev/raw/rawN)"
        depends on BLOCK
index 189efcf..66f779a 100644 (file)
@@ -95,7 +95,6 @@ obj-$(CONFIG_SCx200_GPIO)     += scx200_gpio.o
 obj-$(CONFIG_PC8736x_GPIO)     += pc8736x_gpio.o
 obj-$(CONFIG_NSC_GPIO)         += nsc_gpio.o
 obj-$(CONFIG_CS5535_GPIO)      += cs5535_gpio.o
-obj-$(CONFIG_GPIO_VR41XX)      += vr41xx_giu.o
 obj-$(CONFIG_GPIO_TB0219)      += tb0219.o
 obj-$(CONFIG_TELCLOCK)         += tlclk.o
 
index 140ea10..c02db01 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/cdev.h>
 #include <linux/list.h>
 #include <linux/mm.h>
+#include <asm/pgtable.h>
 #include <asm/io.h>
 
 /*
@@ -75,12 +76,13 @@ static struct class *bsr_class;
 static int bsr_major;
 
 enum {
-       BSR_8   = 0,
-       BSR_16  = 1,
-       BSR_64  = 2,
-       BSR_128 = 3,
-       BSR_UNKNOWN = 4,
-       BSR_MAX = 5,
+       BSR_8    = 0,
+       BSR_16   = 1,
+       BSR_64   = 2,
+       BSR_128  = 3,
+       BSR_4096 = 4,
+       BSR_UNKNOWN = 5,
+       BSR_MAX  = 6,
 };
 
 static unsigned bsr_types[BSR_MAX];
@@ -117,15 +119,22 @@ static int bsr_mmap(struct file *filp, struct vm_area_struct *vma)
 {
        unsigned long size   = vma->vm_end - vma->vm_start;
        struct bsr_dev *dev = filp->private_data;
+       int ret;
 
-       if (size > dev->bsr_len || (size & (PAGE_SIZE-1)))
-               return -EINVAL;
-
-       vma->vm_flags |= (VM_IO | VM_DONTEXPAND);
        vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
 
-       if (io_remap_pfn_range(vma, vma->vm_start, dev->bsr_addr >> PAGE_SHIFT,
-                              size, vma->vm_page_prot))
+       /* check for the case of a small BSR device and map one 4k page for it*/
+       if (dev->bsr_len < PAGE_SIZE && size == PAGE_SIZE)
+               ret = remap_4k_pfn(vma, vma->vm_start, dev->bsr_addr >> 12,
+                                  vma->vm_page_prot);
+       else if (size <= dev->bsr_len)
+               ret = io_remap_pfn_range(vma, vma->vm_start,
+                                        dev->bsr_addr >> PAGE_SHIFT,
+                                        size, vma->vm_page_prot);
+       else
+               return -EINVAL;
+
+       if (ret)
                return -EAGAIN;
 
        return 0;
@@ -205,6 +214,11 @@ static int bsr_add_node(struct device_node *bn)
                cur->bsr_stride = bsr_stride[i];
                cur->bsr_dev    = MKDEV(bsr_major, i + total_bsr_devs);
 
+               /* if we have a bsr_len of > 4k and less then PAGE_SIZE (64k pages) */
+               /* we can only map 4k of it, so only advertise the 4k in sysfs */
+               if (cur->bsr_len > 4096 && cur->bsr_len < PAGE_SIZE)
+                       cur->bsr_len = 4096;
+
                switch(cur->bsr_bytes) {
                case 8:
                        cur->bsr_type = BSR_8;
@@ -218,9 +232,11 @@ static int bsr_add_node(struct device_node *bn)
                case 128:
                        cur->bsr_type = BSR_128;
                        break;
+               case 4096:
+                       cur->bsr_type = BSR_4096;
+                       break;
                default:
                        cur->bsr_type = BSR_UNKNOWN;
-                       printk(KERN_INFO "unknown BSR size %d\n",cur->bsr_bytes);
                }
 
                cur->bsr_num = bsr_types[cur->bsr_type];
index 6062b62..b3ec9b1 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  Driver for TANBAC TB0219 base board.
  *
- *  Copyright (C) 2005  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *  Copyright (C) 2005  Yoichi Yuasa <yuasa@linux-mips.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
@@ -28,7 +28,7 @@
 #include <asm/vr41xx/giu.h>
 #include <asm/vr41xx/tb0219.h>
 
-MODULE_AUTHOR("Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>");
+MODULE_AUTHOR("Yoichi Yuasa <yuasa@linux-mips.org>");
 MODULE_DESCRIPTION("TANBAC TB0219 base board driver");
 MODULE_LICENSE("GPL");
 
index a19e935..913aa8d 100644 (file)
@@ -867,15 +867,22 @@ void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty)
        tty_ldisc_wait_idle(tty);
 
        /*
-        * Shutdown the current line discipline, and reset it to N_TTY.
-        *
-        * FIXME: this MUST get fixed for the new reflocking
+        * Now kill off the ldisc
         */
+       tty_ldisc_close(tty, tty->ldisc);
+       tty_ldisc_put(tty->ldisc);
+       /* Force an oops if we mess this up */
+       tty->ldisc = NULL;
+
+       /* Ensure the next open requests the N_TTY ldisc */
+       tty_set_termios_ldisc(tty, N_TTY);
 
-       tty_ldisc_reinit(tty);
        /* This will need doing differently if we need to lock */
        if (o_tty)
                tty_ldisc_release(o_tty, NULL);
+
+       /* And the memory resources remaining (buffers, termios) will be
+          disposed of when the kref hits zero */
 }
 
 /**
index 54c8372..e69de29 100644 (file)
@@ -1,680 +0,0 @@
-/*
- *  Driver for NEC VR4100 series General-purpose I/O Unit.
- *
- *  Copyright (C) 2002 MontaVista Software Inc.
- *     Author: Yoichi Yuasa <yyuasa@mvista.com or source@mvista.com>
- *  Copyright (C) 2003-2007  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
- *
- *  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/errno.h>
-#include <linux/fs.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/smp_lock.h>
-#include <linux/spinlock.h>
-#include <linux/types.h>
-
-#include <asm/io.h>
-#include <asm/vr41xx/giu.h>
-#include <asm/vr41xx/irq.h>
-#include <asm/vr41xx/vr41xx.h>
-
-MODULE_AUTHOR("Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>");
-MODULE_DESCRIPTION("NEC VR4100 series General-purpose I/O Unit driver");
-MODULE_LICENSE("GPL");
-
-static int major;      /* default is dynamic major device number */
-module_param(major, int, 0);
-MODULE_PARM_DESC(major, "Major device number");
-
-#define GIUIOSELL      0x00
-#define GIUIOSELH      0x02
-#define GIUPIODL       0x04
-#define GIUPIODH       0x06
-#define GIUINTSTATL    0x08
-#define GIUINTSTATH    0x0a
-#define GIUINTENL      0x0c
-#define GIUINTENH      0x0e
-#define GIUINTTYPL     0x10
-#define GIUINTTYPH     0x12
-#define GIUINTALSELL   0x14
-#define GIUINTALSELH   0x16
-#define GIUINTHTSELL   0x18
-#define GIUINTHTSELH   0x1a
-#define GIUPODATL      0x1c
-#define GIUPODATEN     0x1c
-#define GIUPODATH      0x1e
- #define PIOEN0                0x0100
- #define PIOEN1                0x0200
-#define GIUPODAT       0x1e
-#define GIUFEDGEINHL   0x20
-#define GIUFEDGEINHH   0x22
-#define GIUREDGEINHL   0x24
-#define GIUREDGEINHH   0x26
-
-#define GIUUSEUPDN     0x1e0
-#define GIUTERMUPDN    0x1e2
-
-#define GPIO_HAS_PULLUPDOWN_IO         0x0001
-#define GPIO_HAS_OUTPUT_ENABLE         0x0002
-#define GPIO_HAS_INTERRUPT_EDGE_SELECT 0x0100
-
-static spinlock_t giu_lock;
-static unsigned long giu_flags;
-static unsigned int giu_nr_pins;
-
-static void __iomem *giu_base;
-
-#define giu_read(offset)               readw(giu_base + (offset))
-#define giu_write(offset, value)       writew((value), giu_base + (offset))
-
-#define GPIO_PIN_OF_IRQ(irq)   ((irq) - GIU_IRQ_BASE)
-#define GIUINT_HIGH_OFFSET     16
-#define GIUINT_HIGH_MAX                32
-
-static inline uint16_t giu_set(uint16_t offset, uint16_t set)
-{
-       uint16_t data;
-
-       data = giu_read(offset);
-       data |= set;
-       giu_write(offset, data);
-
-       return data;
-}
-
-static inline uint16_t giu_clear(uint16_t offset, uint16_t clear)
-{
-       uint16_t data;
-
-       data = giu_read(offset);
-       data &= ~clear;
-       giu_write(offset, data);
-
-       return data;
-}
-
-static void ack_giuint_low(unsigned int irq)
-{
-       giu_write(GIUINTSTATL, 1 << GPIO_PIN_OF_IRQ(irq));
-}
-
-static void mask_giuint_low(unsigned int irq)
-{
-       giu_clear(GIUINTENL, 1 << GPIO_PIN_OF_IRQ(irq));
-}
-
-static void mask_ack_giuint_low(unsigned int irq)
-{
-       unsigned int pin;
-
-       pin = GPIO_PIN_OF_IRQ(irq);
-       giu_clear(GIUINTENL, 1 << pin);
-       giu_write(GIUINTSTATL, 1 << pin);
-}
-
-static void unmask_giuint_low(unsigned int irq)
-{
-       giu_set(GIUINTENL, 1 << GPIO_PIN_OF_IRQ(irq));
-}
-
-static struct irq_chip giuint_low_irq_chip = {
-       .name           = "GIUINTL",
-       .ack            = ack_giuint_low,
-       .mask           = mask_giuint_low,
-       .mask_ack       = mask_ack_giuint_low,
-       .unmask         = unmask_giuint_low,
-};
-
-static void ack_giuint_high(unsigned int irq)
-{
-       giu_write(GIUINTSTATH, 1 << (GPIO_PIN_OF_IRQ(irq) - GIUINT_HIGH_OFFSET));
-}
-
-static void mask_giuint_high(unsigned int irq)
-{
-       giu_clear(GIUINTENH, 1 << (GPIO_PIN_OF_IRQ(irq) - GIUINT_HIGH_OFFSET));
-}
-
-static void mask_ack_giuint_high(unsigned int irq)
-{
-       unsigned int pin;
-
-       pin = GPIO_PIN_OF_IRQ(irq) - GIUINT_HIGH_OFFSET;
-       giu_clear(GIUINTENH, 1 << pin);
-       giu_write(GIUINTSTATH, 1 << pin);
-}
-
-static void unmask_giuint_high(unsigned int irq)
-{
-       giu_set(GIUINTENH, 1 << (GPIO_PIN_OF_IRQ(irq) - GIUINT_HIGH_OFFSET));
-}
-
-static struct irq_chip giuint_high_irq_chip = {
-       .name           = "GIUINTH",
-       .ack            = ack_giuint_high,
-       .mask           = mask_giuint_high,
-       .mask_ack       = mask_ack_giuint_high,
-       .unmask         = unmask_giuint_high,
-};
-
-static int giu_get_irq(unsigned int irq)
-{
-       uint16_t pendl, pendh, maskl, maskh;
-       int i;
-
-       pendl = giu_read(GIUINTSTATL);
-       pendh = giu_read(GIUINTSTATH);
-       maskl = giu_read(GIUINTENL);
-       maskh = giu_read(GIUINTENH);
-
-       maskl &= pendl;
-       maskh &= pendh;
-
-       if (maskl) {
-               for (i = 0; i < 16; i++) {
-                       if (maskl & (1 << i))
-                               return GIU_IRQ(i);
-               }
-       } else if (maskh) {
-               for (i = 0; i < 16; i++) {
-                       if (maskh & (1 << i))
-                               return GIU_IRQ(i + GIUINT_HIGH_OFFSET);
-               }
-       }
-
-       printk(KERN_ERR "spurious GIU interrupt: %04x(%04x),%04x(%04x)\n",
-              maskl, pendl, maskh, pendh);
-
-       atomic_inc(&irq_err_count);
-
-       return -EINVAL;
-}
-
-void vr41xx_set_irq_trigger(unsigned int pin, irq_trigger_t trigger, irq_signal_t signal)
-{
-       uint16_t mask;
-
-       if (pin < GIUINT_HIGH_OFFSET) {
-               mask = 1 << pin;
-               if (trigger != IRQ_TRIGGER_LEVEL) {
-                       giu_set(GIUINTTYPL, mask);
-                       if (signal == IRQ_SIGNAL_HOLD)
-                               giu_set(GIUINTHTSELL, mask);
-                       else
-                               giu_clear(GIUINTHTSELL, mask);
-                       if (giu_flags & GPIO_HAS_INTERRUPT_EDGE_SELECT) {
-                               switch (trigger) {
-                               case IRQ_TRIGGER_EDGE_FALLING:
-                                       giu_set(GIUFEDGEINHL, mask);
-                                       giu_clear(GIUREDGEINHL, mask);
-                                       break;
-                               case IRQ_TRIGGER_EDGE_RISING:
-                                       giu_clear(GIUFEDGEINHL, mask);
-                                       giu_set(GIUREDGEINHL, mask);
-                                       break;
-                               default:
-                                       giu_set(GIUFEDGEINHL, mask);
-                                       giu_set(GIUREDGEINHL, mask);
-                                       break;
-                               }
-                       }
-                       set_irq_chip_and_handler(GIU_IRQ(pin),
-                                                &giuint_low_irq_chip,
-                                                handle_edge_irq);
-               } else {
-                       giu_clear(GIUINTTYPL, mask);
-                       giu_clear(GIUINTHTSELL, mask);
-                       set_irq_chip_and_handler(GIU_IRQ(pin),
-                                                &giuint_low_irq_chip,
-                                                handle_level_irq);
-               }
-               giu_write(GIUINTSTATL, mask);
-       } else if (pin < GIUINT_HIGH_MAX) {
-               mask = 1 << (pin - GIUINT_HIGH_OFFSET);
-               if (trigger != IRQ_TRIGGER_LEVEL) {
-                       giu_set(GIUINTTYPH, mask);
-                       if (signal == IRQ_SIGNAL_HOLD)
-                               giu_set(GIUINTHTSELH, mask);
-                       else
-                               giu_clear(GIUINTHTSELH, mask);
-                       if (giu_flags & GPIO_HAS_INTERRUPT_EDGE_SELECT) {
-                               switch (trigger) {
-                               case IRQ_TRIGGER_EDGE_FALLING:
-                                       giu_set(GIUFEDGEINHH, mask);
-                                       giu_clear(GIUREDGEINHH, mask);
-                                       break;
-                               case IRQ_TRIGGER_EDGE_RISING:
-                                       giu_clear(GIUFEDGEINHH, mask);
-                                       giu_set(GIUREDGEINHH, mask);
-                                       break;
-                               default:
-                                       giu_set(GIUFEDGEINHH, mask);
-                                       giu_set(GIUREDGEINHH, mask);
-                                       break;
-                               }
-                       }
-                       set_irq_chip_and_handler(GIU_IRQ(pin),
-                                                &giuint_high_irq_chip,
-                                                handle_edge_irq);
-               } else {
-                       giu_clear(GIUINTTYPH, mask);
-                       giu_clear(GIUINTHTSELH, mask);
-                       set_irq_chip_and_handler(GIU_IRQ(pin),
-                                                &giuint_high_irq_chip,
-                                                handle_level_irq);
-               }
-               giu_write(GIUINTSTATH, mask);
-       }
-}
-EXPORT_SYMBOL_GPL(vr41xx_set_irq_trigger);
-
-void vr41xx_set_irq_level(unsigned int pin, irq_level_t level)
-{
-       uint16_t mask;
-
-       if (pin < GIUINT_HIGH_OFFSET) {
-               mask = 1 << pin;
-               if (level == IRQ_LEVEL_HIGH)
-                       giu_set(GIUINTALSELL, mask);
-               else
-                       giu_clear(GIUINTALSELL, mask);
-               giu_write(GIUINTSTATL, mask);
-       } else if (pin < GIUINT_HIGH_MAX) {
-               mask = 1 << (pin - GIUINT_HIGH_OFFSET);
-               if (level == IRQ_LEVEL_HIGH)
-                       giu_set(GIUINTALSELH, mask);
-               else
-                       giu_clear(GIUINTALSELH, mask);
-               giu_write(GIUINTSTATH, mask);
-       }
-}
-EXPORT_SYMBOL_GPL(vr41xx_set_irq_level);
-
-gpio_data_t vr41xx_gpio_get_pin(unsigned int pin)
-{
-       uint16_t reg, mask;
-
-       if (pin >= giu_nr_pins)
-               return GPIO_DATA_INVAL;
-
-       if (pin < 16) {
-               reg = giu_read(GIUPIODL);
-               mask = (uint16_t)1 << pin;
-       } else if (pin < 32) {
-               reg = giu_read(GIUPIODH);
-               mask = (uint16_t)1 << (pin - 16);
-       } else if (pin < 48) {
-               reg = giu_read(GIUPODATL);
-               mask = (uint16_t)1 << (pin - 32);
-       } else {
-               reg = giu_read(GIUPODATH);
-               mask = (uint16_t)1 << (pin - 48);
-       }
-
-       if (reg & mask)
-               return GPIO_DATA_HIGH;
-
-       return GPIO_DATA_LOW;
-}
-EXPORT_SYMBOL_GPL(vr41xx_gpio_get_pin);
-
-int vr41xx_gpio_set_pin(unsigned int pin, gpio_data_t data)
-{
-       uint16_t offset, mask, reg;
-       unsigned long flags;
-
-       if (pin >= giu_nr_pins)
-               return -EINVAL;
-
-       if (pin < 16) {
-               offset = GIUPIODL;
-               mask = (uint16_t)1 << pin;
-       } else if (pin < 32) {
-               offset = GIUPIODH;
-               mask = (uint16_t)1 << (pin - 16);
-       } else if (pin < 48) {
-               offset = GIUPODATL;
-               mask = (uint16_t)1 << (pin - 32);
-       } else {
-               offset = GIUPODATH;
-               mask = (uint16_t)1 << (pin - 48);
-       }
-
-       spin_lock_irqsave(&giu_lock, flags);
-
-       reg = giu_read(offset);
-       if (data == GPIO_DATA_HIGH)
-               reg |= mask;
-       else
-               reg &= ~mask;
-       giu_write(offset, reg);
-
-       spin_unlock_irqrestore(&giu_lock, flags);
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(vr41xx_gpio_set_pin);
-
-int vr41xx_gpio_set_direction(unsigned int pin, gpio_direction_t dir)
-{
-       uint16_t offset, mask, reg;
-       unsigned long flags;
-
-       if (pin >= giu_nr_pins)
-               return -EINVAL;
-
-       if (pin < 16) {
-               offset = GIUIOSELL;
-               mask = (uint16_t)1 << pin;
-       } else if (pin < 32) {
-               offset = GIUIOSELH;
-               mask = (uint16_t)1 << (pin - 16);
-       } else {
-               if (giu_flags & GPIO_HAS_OUTPUT_ENABLE) {
-                       offset = GIUPODATEN;
-                       mask = (uint16_t)1 << (pin - 32);
-               } else {
-                       switch (pin) {
-                       case 48:
-                               offset = GIUPODATH;
-                               mask = PIOEN0;
-                               break;
-                       case 49:
-                               offset = GIUPODATH;
-                               mask = PIOEN1;
-                               break;
-                       default:
-                               return -EINVAL;
-                       }
-               }
-       }
-
-       spin_lock_irqsave(&giu_lock, flags);
-
-       reg = giu_read(offset);
-       if (dir == GPIO_OUTPUT)
-               reg |= mask;
-       else
-               reg &= ~mask;
-       giu_write(offset, reg);
-
-       spin_unlock_irqrestore(&giu_lock, flags);
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(vr41xx_gpio_set_direction);
-
-int vr41xx_gpio_pullupdown(unsigned int pin, gpio_pull_t pull)
-{
-       uint16_t reg, mask;
-       unsigned long flags;
-
-       if ((giu_flags & GPIO_HAS_PULLUPDOWN_IO) != GPIO_HAS_PULLUPDOWN_IO)
-               return -EPERM;
-
-       if (pin >= 15)
-               return -EINVAL;
-
-       mask = (uint16_t)1 << pin;
-
-       spin_lock_irqsave(&giu_lock, flags);
-
-       if (pull == GPIO_PULL_UP || pull == GPIO_PULL_DOWN) {
-               reg = giu_read(GIUTERMUPDN);
-               if (pull == GPIO_PULL_UP)
-                       reg |= mask;
-               else
-                       reg &= ~mask;
-               giu_write(GIUTERMUPDN, reg);
-
-               reg = giu_read(GIUUSEUPDN);
-               reg |= mask;
-               giu_write(GIUUSEUPDN, reg);
-       } else {
-               reg = giu_read(GIUUSEUPDN);
-               reg &= ~mask;
-               giu_write(GIUUSEUPDN, reg);
-       }
-
-       spin_unlock_irqrestore(&giu_lock, flags);
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(vr41xx_gpio_pullupdown);
-
-static ssize_t gpio_read(struct file *file, char __user *buf, size_t len,
-                         loff_t *ppos)
-{
-       unsigned int pin;
-       char value = '0';
-
-       pin = iminor(file->f_path.dentry->d_inode);
-       if (pin >= giu_nr_pins)
-               return -EBADF;
-
-       if (vr41xx_gpio_get_pin(pin) == GPIO_DATA_HIGH)
-               value = '1';
-
-       if (len <= 0)
-               return -EFAULT;
-
-       if (put_user(value, buf))
-               return -EFAULT;
-
-       return 1;
-}
-
-static ssize_t gpio_write(struct file *file, const char __user *data,
-                          size_t len, loff_t *ppos)
-{
-       unsigned int pin;
-       size_t i;
-       char c;
-       int retval = 0;
-
-       pin = iminor(file->f_path.dentry->d_inode);
-       if (pin >= giu_nr_pins)
-               return -EBADF;
-
-       for (i = 0; i < len; i++) {
-               if (get_user(c, data + i))
-                       return -EFAULT;
-
-               switch (c) {
-               case '0':
-                       retval = vr41xx_gpio_set_pin(pin, GPIO_DATA_LOW);
-                       break;
-               case '1':
-                       retval = vr41xx_gpio_set_pin(pin, GPIO_DATA_HIGH);
-                       break;
-               case 'D':
-                       printk(KERN_INFO "GPIO%d: pull down\n", pin);
-                       retval = vr41xx_gpio_pullupdown(pin, GPIO_PULL_DOWN);
-                       break;
-               case 'd':
-                       printk(KERN_INFO "GPIO%d: pull up/down disable\n", pin);
-                       retval = vr41xx_gpio_pullupdown(pin, GPIO_PULL_DISABLE);
-                       break;
-               case 'I':
-                       printk(KERN_INFO "GPIO%d: input\n", pin);
-                       retval = vr41xx_gpio_set_direction(pin, GPIO_INPUT);
-                       break;
-               case 'O':
-                       printk(KERN_INFO "GPIO%d: output\n", pin);
-                       retval = vr41xx_gpio_set_direction(pin, GPIO_OUTPUT);
-                       break;
-               case 'o':
-                       printk(KERN_INFO "GPIO%d: output disable\n", pin);
-                       retval = vr41xx_gpio_set_direction(pin, GPIO_OUTPUT_DISABLE);
-                       break;
-               case 'P':
-                       printk(KERN_INFO "GPIO%d: pull up\n", pin);
-                       retval = vr41xx_gpio_pullupdown(pin, GPIO_PULL_UP);
-                       break;
-               case 'p':
-                       printk(KERN_INFO "GPIO%d: pull up/down disable\n", pin);
-                       retval = vr41xx_gpio_pullupdown(pin, GPIO_PULL_DISABLE);
-                       break;
-               default:
-                       break;
-               }
-
-               if (retval < 0)
-                       break;
-       }
-
-       return i;
-}
-
-static int gpio_open(struct inode *inode, struct file *file)
-{
-       unsigned int pin;
-
-       cycle_kernel_lock();
-       pin = iminor(inode);
-       if (pin >= giu_nr_pins)
-               return -EBADF;
-
-       return nonseekable_open(inode, file);
-}
-
-static int gpio_release(struct inode *inode, struct file *file)
-{
-       unsigned int pin;
-
-       pin = iminor(inode);
-       if (pin >= giu_nr_pins)
-               return -EBADF;
-
-       return 0;
-}
-
-static const struct file_operations gpio_fops = {
-       .owner          = THIS_MODULE,
-       .read           = gpio_read,
-       .write          = gpio_write,
-       .open           = gpio_open,
-       .release        = gpio_release,
-};
-
-static int __devinit giu_probe(struct platform_device *dev)
-{
-       struct resource *res;
-       unsigned int trigger, i, pin;
-       struct irq_chip *chip;
-       int irq, retval;
-
-       switch (dev->id) {
-       case GPIO_50PINS_PULLUPDOWN:
-               giu_flags = GPIO_HAS_PULLUPDOWN_IO;
-               giu_nr_pins = 50;
-               break;
-       case GPIO_36PINS:
-               giu_nr_pins = 36;
-               break;
-       case GPIO_48PINS_EDGE_SELECT:
-               giu_flags = GPIO_HAS_INTERRUPT_EDGE_SELECT;
-               giu_nr_pins = 48;
-               break;
-       default:
-               printk(KERN_ERR "GIU: unknown ID %d\n", dev->id);
-               return -ENODEV;
-       }
-
-       res = platform_get_resource(dev, IORESOURCE_MEM, 0);
-       if (!res)
-               return -EBUSY;
-
-       giu_base = ioremap(res->start, res->end - res->start + 1);
-       if (!giu_base)
-               return -ENOMEM;
-
-       retval = register_chrdev(major, "GIU", &gpio_fops);
-       if (retval < 0) {
-               iounmap(giu_base);
-               giu_base = NULL;
-               return retval;
-       }
-
-       if (major == 0) {
-               major = retval;
-               printk(KERN_INFO "GIU: major number %d\n", major);
-       }
-
-       spin_lock_init(&giu_lock);
-
-       giu_write(GIUINTENL, 0);
-       giu_write(GIUINTENH, 0);
-
-       trigger = giu_read(GIUINTTYPH) << 16;
-       trigger |= giu_read(GIUINTTYPL);
-       for (i = GIU_IRQ_BASE; i <= GIU_IRQ_LAST; i++) {
-               pin = GPIO_PIN_OF_IRQ(i);
-               if (pin < GIUINT_HIGH_OFFSET)
-                       chip = &giuint_low_irq_chip;
-               else
-                       chip = &giuint_high_irq_chip;
-
-               if (trigger & (1 << pin))
-                       set_irq_chip_and_handler(i, chip, handle_edge_irq);
-               else
-                       set_irq_chip_and_handler(i, chip, handle_level_irq);
-
-       }
-
-       irq = platform_get_irq(dev, 0);
-       if (irq < 0 || irq >= nr_irqs)
-               return -EBUSY;
-
-       return cascade_irq(irq, giu_get_irq);
-}
-
-static int __devexit giu_remove(struct platform_device *dev)
-{
-       if (giu_base) {
-               iounmap(giu_base);
-               giu_base = NULL;
-       }
-
-       return 0;
-}
-
-static struct platform_driver giu_device_driver = {
-       .probe          = giu_probe,
-       .remove         = __devexit_p(giu_remove),
-       .driver         = {
-               .name   = "GIU",
-               .owner  = THIS_MODULE,
-       },
-};
-
-static int __init vr41xx_giu_init(void)
-{
-       return platform_driver_register(&giu_device_driver);
-}
-
-static void __exit vr41xx_giu_exit(void)
-{
-       platform_driver_unregister(&giu_device_driver);
-}
-
-module_init(vr41xx_giu_init);
-module_exit(vr41xx_giu_exit);
index 9ffb05f..93c2322 100644 (file)
@@ -161,7 +161,7 @@ static void sh_tmu_set_next(struct sh_tmu_priv *p, unsigned long delta,
        if (periodic)
                sh_tmu_write(p, TCOR, delta);
        else
-               sh_tmu_write(p, TCOR, 0);
+               sh_tmu_write(p, TCOR, 0xffffffff);
 
        sh_tmu_write(p, TCNT, delta);
 
index c5afc98..85e5dc0 100644 (file)
@@ -202,9 +202,8 @@ static void cn_proc_ack(int err, int rcvd_seq, int rcvd_ack)
  * cn_proc_mcast_ctl
  * @data: message sent from userspace via the connector
  */
-static void cn_proc_mcast_ctl(void *data)
+static void cn_proc_mcast_ctl(struct cn_msg *msg)
 {
-       struct cn_msg *msg = data;
        enum proc_cn_mcast_op *mc_op = NULL;
        int err = 0;
 
index 408c2af..4a1dfe1 100644 (file)
@@ -87,7 +87,9 @@ void cn_queue_wrapper(struct work_struct *work)
        kfree(d->free);
 }
 
-static struct cn_callback_entry *cn_queue_alloc_callback_entry(char *name, struct cb_id *id, void (*callback)(void *))
+static struct cn_callback_entry *
+cn_queue_alloc_callback_entry(char *name, struct cb_id *id,
+                             void (*callback)(struct cn_msg *))
 {
        struct cn_callback_entry *cbq;
 
@@ -120,7 +122,8 @@ int cn_cb_equal(struct cb_id *i1, struct cb_id *i2)
        return ((i1->idx == i2->idx) && (i1->val == i2->val));
 }
 
-int cn_queue_add_callback(struct cn_queue_dev *dev, char *name, struct cb_id *id, void (*callback)(void *))
+int cn_queue_add_callback(struct cn_queue_dev *dev, char *name, struct cb_id *id,
+                         void (*callback)(struct cn_msg *))
 {
        struct cn_callback_entry *cbq, *__cbq;
        int found = 0;
index 08b2500..74f52af 100644 (file)
@@ -269,7 +269,8 @@ static void cn_notify(struct cb_id *id, u32 notify_event)
  *
  * May sleep.
  */
-int cn_add_callback(struct cb_id *id, char *name, void (*callback)(void *))
+int cn_add_callback(struct cb_id *id, char *name,
+                   void (*callback)(struct cn_msg *))
 {
        int err;
        struct cn_dev *dev = &cdev;
@@ -351,9 +352,8 @@ static int cn_ctl_msg_equals(struct cn_ctl_msg *m1, struct cn_ctl_msg *m2)
  *
  * Used for notification of a request's processing.
  */
-static void cn_callback(void *data)
+static void cn_callback(struct cn_msg *msg)
 {
-       struct cn_msg *msg = data;
        struct cn_ctl_msg *ctl;
        struct cn_ctl_entry *ent;
        u32 size;
index c36bf40..858fe60 100644 (file)
@@ -754,13 +754,13 @@ static void amd64_cpu_display_info(struct amd64_pvt *pvt)
 static enum edac_type amd64_determine_edac_cap(struct amd64_pvt *pvt)
 {
        int bit;
-       enum dev_type edac_cap = EDAC_NONE;
+       enum dev_type edac_cap = EDAC_FLAG_NONE;
 
        bit = (boot_cpu_data.x86 > 0xf || pvt->ext_model >= OPTERON_CPU_REV_F)
                ? 19
                : 17;
 
-       if (pvt->dclr0 >> BIT(bit))
+       if (pvt->dclr0 & BIT(bit))
                edac_cap = EDAC_FLAG_SECDED;
 
        return edac_cap;
@@ -1269,7 +1269,7 @@ static int f10_early_channel_count(struct amd64_pvt *pvt)
        if (channels == 0)
                channels = 1;
 
-       debugf0("DIMM count= %d\n", channels);
+       debugf0("MCT channel count: %d\n", channels);
 
        return channels;
 
@@ -2966,7 +2966,12 @@ static int amd64_check_ecc_enabled(struct amd64_pvt *pvt)
                                "    Use of the override can cause "
                                "unknown side effects.\n");
                        ret = -ENODEV;
-               }
+               } else
+                       /*
+                        * enable further driver loading if ECC enable is
+                        * overridden.
+                        */
+                       ret = 0;
        } else {
                amd64_printk(KERN_INFO,
                        "ECC is enabled by BIOS, Proceeding "
@@ -3006,7 +3011,6 @@ static void amd64_setup_mci_misc_attributes(struct mem_ctl_info *mci)
 
        mci->mtype_cap          = MEM_FLAG_DDR2 | MEM_FLAG_RDDR2;
        mci->edac_ctl_cap       = EDAC_FLAG_NONE;
-       mci->edac_cap           = EDAC_FLAG_NONE;
 
        if (pvt->nbcap & K8_NBCAP_SECDED)
                mci->edac_ctl_cap |= EDAC_FLAG_SECDED;
@@ -3052,7 +3056,7 @@ static int amd64_probe_one_instance(struct pci_dev *dram_f2_ctl,
        if (!pvt)
                goto err_exit;
 
-       pvt->mc_node_id = get_mc_node_id_from_pdev(dram_f2_ctl);
+       pvt->mc_node_id = get_node_id(dram_f2_ctl);
 
        pvt->dram_f2_ctl        = dram_f2_ctl;
        pvt->ext_model          = boot_cpu_data.x86_model >> 4;
@@ -3179,8 +3183,7 @@ static int __devinit amd64_init_one_instance(struct pci_dev *pdev,
 {
        int ret = 0;
 
-       debugf0("(MC node=%d,mc_type='%s')\n",
-               get_mc_node_id_from_pdev(pdev),
+       debugf0("(MC node=%d,mc_type='%s')\n", get_node_id(pdev),
                get_amd_family_name(mc_type->driver_data));
 
        ret = pci_enable_device(pdev);
@@ -3319,15 +3322,17 @@ static int __init amd64_edac_init(void)
 
                err = amd64_init_2nd_stage(pvt_lookup[nb]);
                if (err)
-                       goto err_exit;
+                       goto err_2nd_stage;
        }
 
        amd64_setup_pci_device();
 
        return 0;
 
+err_2nd_stage:
+       debugf0("2nd stage failed\n");
+
 err_exit:
-       debugf0("'finish_setup' stage failed\n");
        pci_unregister_driver(&amd64_pci_driver);
 
        return err;
index a159957..ba73015 100644 (file)
@@ -444,7 +444,7 @@ enum {
 #define K8_MSR_MC4ADDR                 0x0412
 
 /* AMD sets the first MC device at device ID 0x18. */
-static inline int get_mc_node_id_from_pdev(struct pci_dev *pdev)
+static inline int get_node_id(struct pci_dev *pdev)
 {
        return PCI_SLOT(pdev->devfn) - 0x18;
 }
index 3493c6b..871c13b 100644 (file)
@@ -150,6 +150,8 @@ enum mem_type {
        MEM_FB_DDR2,            /* fully buffered DDR2 */
        MEM_RDDR2,              /* Registered DDR2 RAM */
        MEM_XDR,                /* Rambus XDR */
+       MEM_DDR3,               /* DDR3 RAM */
+       MEM_RDDR3,              /* Registered DDR3 RAM */
 };
 
 #define MEM_FLAG_EMPTY         BIT(MEM_EMPTY)
@@ -167,6 +169,8 @@ enum mem_type {
 #define MEM_FLAG_FB_DDR2        BIT(MEM_FB_DDR2)
 #define MEM_FLAG_RDDR2          BIT(MEM_RDDR2)
 #define MEM_FLAG_XDR            BIT(MEM_XDR)
+#define MEM_FLAG_DDR3           BIT(MEM_DDR3)
+#define MEM_FLAG_RDDR3          BIT(MEM_RDDR3)
 
 /* chipset Error Detection and Correction capabilities and mode */
 enum edac_type {
index ad218fe..e1d4ce0 100644 (file)
@@ -94,7 +94,9 @@ static const char *mem_types[] = {
        [MEM_DDR2] = "Unbuffered-DDR2",
        [MEM_FB_DDR2] = "FullyBuffered-DDR2",
        [MEM_RDDR2] = "Registered-DDR2",
-       [MEM_XDR] = "XDR"
+       [MEM_XDR] = "XDR",
+       [MEM_DDR3] = "Unbuffered-DDR3",
+       [MEM_RDDR3] = "Registered-DDR3"
 };
 
 static const char *dev_types[] = {
index 7c8c2d7..3f2ccfc 100644 (file)
@@ -757,6 +757,9 @@ static void __devinit mpc85xx_init_csrows(struct mem_ctl_info *mci)
                case DSC_SDTYPE_DDR2:
                        mtype = MEM_RDDR2;
                        break;
+               case DSC_SDTYPE_DDR3:
+                       mtype = MEM_RDDR3;
+                       break;
                default:
                        mtype = MEM_UNKNOWN;
                        break;
@@ -769,6 +772,9 @@ static void __devinit mpc85xx_init_csrows(struct mem_ctl_info *mci)
                case DSC_SDTYPE_DDR2:
                        mtype = MEM_DDR2;
                        break;
+               case DSC_SDTYPE_DDR3:
+                       mtype = MEM_DDR3;
+                       break;
                default:
                        mtype = MEM_UNKNOWN;
                        break;
index 135b353..52432ee 100644 (file)
@@ -53,6 +53,7 @@
 
 #define DSC_SDTYPE_DDR         0x02000000
 #define DSC_SDTYPE_DDR2                0x03000000
+#define DSC_SDTYPE_DDR3                0x07000000
 #define DSC_X32_EN     0x00000020
 
 /* Err_Int_En */
index 3582c39..96dda81 100644 (file)
@@ -79,6 +79,12 @@ config GPIO_XILINX
        help
          Say yes here to support the Xilinx FPGA GPIO device
 
+config GPIO_VR41XX
+       tristate "NEC VR4100 series General-purpose I/O Uint support"
+       depends on CPU_VR41XX
+       help
+         Say yes here to support the NEC VR4100 series General-purpose I/O Uint
+
 comment "I2C GPIO expanders:"
 
 config GPIO_MAX732X
index ef90203..9244c6f 100644 (file)
@@ -13,3 +13,4 @@ obj-$(CONFIG_GPIO_PL061)      += pl061.o
 obj-$(CONFIG_GPIO_TWL4030)     += twl4030-gpio.o
 obj-$(CONFIG_GPIO_XILINX)      += xilinx_gpio.o
 obj-$(CONFIG_GPIO_BT8XX)       += bt8xxgpio.o
+obj-$(CONFIG_GPIO_VR41XX)      += vr41xx_giu.o
index aa8e7cb..4ee4c83 100644 (file)
@@ -109,6 +109,16 @@ static void pl061_set_value(struct gpio_chip *gc, unsigned offset, int value)
        writeb(!!value << offset, chip->base + (1 << (offset + 2)));
 }
 
+static int pl061_to_irq(struct gpio_chip *gc, unsigned offset)
+{
+       struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc);
+
+       if (chip->irq_base == (unsigned) -1)
+               return -EINVAL;
+
+       return chip->irq_base + offset;
+}
+
 /*
  * PL061 GPIO IRQ
  */
@@ -200,7 +210,7 @@ static void pl061_irq_handler(unsigned irq, struct irq_desc *desc)
        desc->chip->ack(irq);
        list_for_each(ptr, chip_list) {
                unsigned long pending;
-               int gpio;
+               int offset;
 
                chip = list_entry(ptr, struct pl061_gpio, list);
                pending = readb(chip->base + GPIOMIS);
@@ -209,8 +219,8 @@ static void pl061_irq_handler(unsigned irq, struct irq_desc *desc)
                if (pending == 0)
                        continue;
 
-               for_each_bit(gpio, &pending, PL061_GPIO_NR)
-                       generic_handle_irq(gpio_to_irq(gpio));
+               for_each_bit(offset, &pending, PL061_GPIO_NR)
+                       generic_handle_irq(pl061_to_irq(&chip->gc, offset));
        }
        desc->chip->unmask(irq);
 }
@@ -221,7 +231,7 @@ static int __init pl061_probe(struct amba_device *dev, struct amba_id *id)
        struct pl061_gpio *chip;
        struct list_head *chip_list;
        int ret, irq, i;
-       static unsigned long init_irq[BITS_TO_LONGS(NR_IRQS)];
+       static DECLARE_BITMAP(init_irq, NR_IRQS);
 
        pdata = dev->dev.platform_data;
        if (pdata == NULL)
@@ -251,6 +261,7 @@ static int __init pl061_probe(struct amba_device *dev, struct amba_id *id)
        chip->gc.direction_output = pl061_direction_output;
        chip->gc.get = pl061_get_value;
        chip->gc.set = pl061_set_value;
+       chip->gc.to_irq = pl061_to_irq;
        chip->gc.base = pdata->gpio_base;
        chip->gc.ngpio = PL061_GPIO_NR;
        chip->gc.label = dev_name(&dev->dev);
@@ -280,6 +291,7 @@ static int __init pl061_probe(struct amba_device *dev, struct amba_id *id)
        if (!test_and_set_bit(irq, init_irq)) { /* list initialized? */
                chip_list = kmalloc(sizeof(*chip_list), GFP_KERNEL);
                if (chip_list == NULL) {
+                       clear_bit(irq, init_irq);
                        ret = -ENOMEM;
                        goto iounmap;
                }
diff --git a/drivers/gpio/vr41xx_giu.c b/drivers/gpio/vr41xx_giu.c
new file mode 100644 (file)
index 0000000..b70e061
--- /dev/null
@@ -0,0 +1,586 @@
+/*
+ *  Driver for NEC VR4100 series General-purpose I/O Unit.
+ *
+ *  Copyright (C) 2002 MontaVista Software Inc.
+ *     Author: Yoichi Yuasa <source@mvista.com>
+ *  Copyright (C) 2003-2009  Yoichi Yuasa <yuasa@linux-mips.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 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/errno.h>
+#include <linux/fs.h>
+#include <linux/gpio.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/smp_lock.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+
+#include <asm/vr41xx/giu.h>
+#include <asm/vr41xx/irq.h>
+#include <asm/vr41xx/vr41xx.h>
+
+MODULE_AUTHOR("Yoichi Yuasa <yuasa@linux-mips.org>");
+MODULE_DESCRIPTION("NEC VR4100 series General-purpose I/O Unit driver");
+MODULE_LICENSE("GPL");
+
+#define GIUIOSELL      0x00
+#define GIUIOSELH      0x02
+#define GIUPIODL       0x04
+#define GIUPIODH       0x06
+#define GIUINTSTATL    0x08
+#define GIUINTSTATH    0x0a
+#define GIUINTENL      0x0c
+#define GIUINTENH      0x0e
+#define GIUINTTYPL     0x10
+#define GIUINTTYPH     0x12
+#define GIUINTALSELL   0x14
+#define GIUINTALSELH   0x16
+#define GIUINTHTSELL   0x18
+#define GIUINTHTSELH   0x1a
+#define GIUPODATL      0x1c
+#define GIUPODATEN     0x1c
+#define GIUPODATH      0x1e
+ #define PIOEN0                0x0100
+ #define PIOEN1                0x0200
+#define GIUPODAT       0x1e
+#define GIUFEDGEINHL   0x20
+#define GIUFEDGEINHH   0x22
+#define GIUREDGEINHL   0x24
+#define GIUREDGEINHH   0x26
+
+#define GIUUSEUPDN     0x1e0
+#define GIUTERMUPDN    0x1e2
+
+#define GPIO_HAS_PULLUPDOWN_IO         0x0001
+#define GPIO_HAS_OUTPUT_ENABLE         0x0002
+#define GPIO_HAS_INTERRUPT_EDGE_SELECT 0x0100
+
+enum {
+       GPIO_INPUT,
+       GPIO_OUTPUT,
+};
+
+static DEFINE_SPINLOCK(giu_lock);
+static unsigned long giu_flags;
+
+static void __iomem *giu_base;
+
+#define giu_read(offset)               readw(giu_base + (offset))
+#define giu_write(offset, value)       writew((value), giu_base + (offset))
+
+#define GPIO_PIN_OF_IRQ(irq)   ((irq) - GIU_IRQ_BASE)
+#define GIUINT_HIGH_OFFSET     16
+#define GIUINT_HIGH_MAX                32
+
+static inline u16 giu_set(u16 offset, u16 set)
+{
+       u16 data;
+
+       data = giu_read(offset);
+       data |= set;
+       giu_write(offset, data);
+
+       return data;
+}
+
+static inline u16 giu_clear(u16 offset, u16 clear)
+{
+       u16 data;
+
+       data = giu_read(offset);
+       data &= ~clear;
+       giu_write(offset, data);
+
+       return data;
+}
+
+static void ack_giuint_low(unsigned int irq)
+{
+       giu_write(GIUINTSTATL, 1 << GPIO_PIN_OF_IRQ(irq));
+}
+
+static void mask_giuint_low(unsigned int irq)
+{
+       giu_clear(GIUINTENL, 1 << GPIO_PIN_OF_IRQ(irq));
+}
+
+static void mask_ack_giuint_low(unsigned int irq)
+{
+       unsigned int pin;
+
+       pin = GPIO_PIN_OF_IRQ(irq);
+       giu_clear(GIUINTENL, 1 << pin);
+       giu_write(GIUINTSTATL, 1 << pin);
+}
+
+static void unmask_giuint_low(unsigned int irq)
+{
+       giu_set(GIUINTENL, 1 << GPIO_PIN_OF_IRQ(irq));
+}
+
+static struct irq_chip giuint_low_irq_chip = {
+       .name           = "GIUINTL",
+       .ack            = ack_giuint_low,
+       .mask           = mask_giuint_low,
+       .mask_ack       = mask_ack_giuint_low,
+       .unmask         = unmask_giuint_low,
+};
+
+static void ack_giuint_high(unsigned int irq)
+{
+       giu_write(GIUINTSTATH,
+                 1 << (GPIO_PIN_OF_IRQ(irq) - GIUINT_HIGH_OFFSET));
+}
+
+static void mask_giuint_high(unsigned int irq)
+{
+       giu_clear(GIUINTENH, 1 << (GPIO_PIN_OF_IRQ(irq) - GIUINT_HIGH_OFFSET));
+}
+
+static void mask_ack_giuint_high(unsigned int irq)
+{
+       unsigned int pin;
+
+       pin = GPIO_PIN_OF_IRQ(irq) - GIUINT_HIGH_OFFSET;
+       giu_clear(GIUINTENH, 1 << pin);
+       giu_write(GIUINTSTATH, 1 << pin);
+}
+
+static void unmask_giuint_high(unsigned int irq)
+{
+       giu_set(GIUINTENH, 1 << (GPIO_PIN_OF_IRQ(irq) - GIUINT_HIGH_OFFSET));
+}
+
+static struct irq_chip giuint_high_irq_chip = {
+       .name           = "GIUINTH",
+       .ack            = ack_giuint_high,
+       .mask           = mask_giuint_high,
+       .mask_ack       = mask_ack_giuint_high,
+       .unmask         = unmask_giuint_high,
+};
+
+static int giu_get_irq(unsigned int irq)
+{
+       u16 pendl, pendh, maskl, maskh;
+       int i;
+
+       pendl = giu_read(GIUINTSTATL);
+       pendh = giu_read(GIUINTSTATH);
+       maskl = giu_read(GIUINTENL);
+       maskh = giu_read(GIUINTENH);
+
+       maskl &= pendl;
+       maskh &= pendh;
+
+       if (maskl) {
+               for (i = 0; i < 16; i++) {
+                       if (maskl & (1 << i))
+                               return GIU_IRQ(i);
+               }
+       } else if (maskh) {
+               for (i = 0; i < 16; i++) {
+                       if (maskh & (1 << i))
+                               return GIU_IRQ(i + GIUINT_HIGH_OFFSET);
+               }
+       }
+
+       printk(KERN_ERR "spurious GIU interrupt: %04x(%04x),%04x(%04x)\n",
+              maskl, pendl, maskh, pendh);
+
+       atomic_inc(&irq_err_count);
+
+       return -EINVAL;
+}
+
+void vr41xx_set_irq_trigger(unsigned int pin, irq_trigger_t trigger,
+                           irq_signal_t signal)
+{
+       u16 mask;
+
+       if (pin < GIUINT_HIGH_OFFSET) {
+               mask = 1 << pin;
+               if (trigger != IRQ_TRIGGER_LEVEL) {
+                       giu_set(GIUINTTYPL, mask);
+                       if (signal == IRQ_SIGNAL_HOLD)
+                               giu_set(GIUINTHTSELL, mask);
+                       else
+                               giu_clear(GIUINTHTSELL, mask);
+                       if (giu_flags & GPIO_HAS_INTERRUPT_EDGE_SELECT) {
+                               switch (trigger) {
+                               case IRQ_TRIGGER_EDGE_FALLING:
+                                       giu_set(GIUFEDGEINHL, mask);
+                                       giu_clear(GIUREDGEINHL, mask);
+                                       break;
+                               case IRQ_TRIGGER_EDGE_RISING:
+                                       giu_clear(GIUFEDGEINHL, mask);
+                                       giu_set(GIUREDGEINHL, mask);
+                                       break;
+                               default:
+                                       giu_set(GIUFEDGEINHL, mask);
+                                       giu_set(GIUREDGEINHL, mask);
+                                       break;
+                               }
+                       }
+                       set_irq_chip_and_handler(GIU_IRQ(pin),
+                                                &giuint_low_irq_chip,
+                                                handle_edge_irq);
+               } else {
+                       giu_clear(GIUINTTYPL, mask);
+                       giu_clear(GIUINTHTSELL, mask);
+                       set_irq_chip_and_handler(GIU_IRQ(pin),
+                                                &giuint_low_irq_chip,
+                                                handle_level_irq);
+               }
+               giu_write(GIUINTSTATL, mask);
+       } else if (pin < GIUINT_HIGH_MAX) {
+               mask = 1 << (pin - GIUINT_HIGH_OFFSET);
+               if (trigger != IRQ_TRIGGER_LEVEL) {
+                       giu_set(GIUINTTYPH, mask);
+                       if (signal == IRQ_SIGNAL_HOLD)
+                               giu_set(GIUINTHTSELH, mask);
+                       else
+                               giu_clear(GIUINTHTSELH, mask);
+                       if (giu_flags & GPIO_HAS_INTERRUPT_EDGE_SELECT) {
+                               switch (trigger) {
+                               case IRQ_TRIGGER_EDGE_FALLING:
+                                       giu_set(GIUFEDGEINHH, mask);
+                                       giu_clear(GIUREDGEINHH, mask);
+                                       break;
+                               case IRQ_TRIGGER_EDGE_RISING:
+                                       giu_clear(GIUFEDGEINHH, mask);
+                                       giu_set(GIUREDGEINHH, mask);
+                                       break;
+                               default:
+                                       giu_set(GIUFEDGEINHH, mask);
+                                       giu_set(GIUREDGEINHH, mask);
+                                       break;
+                               }
+                       }
+                       set_irq_chip_and_handler(GIU_IRQ(pin),
+                                                &giuint_high_irq_chip,
+                                                handle_edge_irq);
+               } else {
+                       giu_clear(GIUINTTYPH, mask);
+                       giu_clear(GIUINTHTSELH, mask);
+                       set_irq_chip_and_handler(GIU_IRQ(pin),
+                                                &giuint_high_irq_chip,
+                                                handle_level_irq);
+               }
+               giu_write(GIUINTSTATH, mask);
+       }
+}
+EXPORT_SYMBOL_GPL(vr41xx_set_irq_trigger);
+
+void vr41xx_set_irq_level(unsigned int pin, irq_level_t level)
+{
+       u16 mask;
+
+       if (pin < GIUINT_HIGH_OFFSET) {
+               mask = 1 << pin;
+               if (level == IRQ_LEVEL_HIGH)
+                       giu_set(GIUINTALSELL, mask);
+               else
+                       giu_clear(GIUINTALSELL, mask);
+               giu_write(GIUINTSTATL, mask);
+       } else if (pin < GIUINT_HIGH_MAX) {
+               mask = 1 << (pin - GIUINT_HIGH_OFFSET);
+               if (level == IRQ_LEVEL_HIGH)
+                       giu_set(GIUINTALSELH, mask);
+               else
+                       giu_clear(GIUINTALSELH, mask);
+               giu_write(GIUINTSTATH, mask);
+       }
+}
+EXPORT_SYMBOL_GPL(vr41xx_set_irq_level);
+
+static int giu_set_direction(struct gpio_chip *chip, unsigned pin, int dir)
+{
+       u16 offset, mask, reg;
+       unsigned long flags;
+
+       if (pin >= chip->ngpio)
+               return -EINVAL;
+
+       if (pin < 16) {
+               offset = GIUIOSELL;
+               mask = 1 << pin;
+       } else if (pin < 32) {
+               offset = GIUIOSELH;
+               mask = 1 << (pin - 16);
+       } else {
+               if (giu_flags & GPIO_HAS_OUTPUT_ENABLE) {
+                       offset = GIUPODATEN;
+                       mask = 1 << (pin - 32);
+               } else {
+                       switch (pin) {
+                       case 48:
+                               offset = GIUPODATH;
+                               mask = PIOEN0;
+                               break;
+                       case 49:
+                               offset = GIUPODATH;
+                               mask = PIOEN1;
+                               break;
+                       default:
+                               return -EINVAL;
+                       }
+               }
+       }
+
+       spin_lock_irqsave(&giu_lock, flags);
+
+       reg = giu_read(offset);
+       if (dir == GPIO_OUTPUT)
+               reg |= mask;
+       else
+               reg &= ~mask;
+       giu_write(offset, reg);
+
+       spin_unlock_irqrestore(&giu_lock, flags);
+
+       return 0;
+}
+
+int vr41xx_gpio_pullupdown(unsigned int pin, gpio_pull_t pull)
+{
+       u16 reg, mask;
+       unsigned long flags;
+
+       if ((giu_flags & GPIO_HAS_PULLUPDOWN_IO) != GPIO_HAS_PULLUPDOWN_IO)
+               return -EPERM;
+
+       if (pin >= 15)
+               return -EINVAL;
+
+       mask = 1 << pin;
+
+       spin_lock_irqsave(&giu_lock, flags);
+
+       if (pull == GPIO_PULL_UP || pull == GPIO_PULL_DOWN) {
+               reg = giu_read(GIUTERMUPDN);
+               if (pull == GPIO_PULL_UP)
+                       reg |= mask;
+               else
+                       reg &= ~mask;
+               giu_write(GIUTERMUPDN, reg);
+
+               reg = giu_read(GIUUSEUPDN);
+               reg |= mask;
+               giu_write(GIUUSEUPDN, reg);
+       } else {
+               reg = giu_read(GIUUSEUPDN);
+               reg &= ~mask;
+               giu_write(GIUUSEUPDN, reg);
+       }
+
+       spin_unlock_irqrestore(&giu_lock, flags);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(vr41xx_gpio_pullupdown);
+
+static int vr41xx_gpio_get(struct gpio_chip *chip, unsigned pin)
+{
+       u16 reg, mask;
+
+       if (pin >= chip->ngpio)
+               return -EINVAL;
+
+       if (pin < 16) {
+               reg = giu_read(GIUPIODL);
+               mask = 1 << pin;
+       } else if (pin < 32) {
+               reg = giu_read(GIUPIODH);
+               mask = 1 << (pin - 16);
+       } else if (pin < 48) {
+               reg = giu_read(GIUPODATL);
+               mask = 1 << (pin - 32);
+       } else {
+               reg = giu_read(GIUPODATH);
+               mask = 1 << (pin - 48);
+       }
+
+       if (reg & mask)
+               return 1;
+
+       return 0;
+}
+
+static void vr41xx_gpio_set(struct gpio_chip *chip, unsigned pin,
+                           int value)
+{
+       u16 offset, mask, reg;
+       unsigned long flags;
+
+       if (pin >= chip->ngpio)
+               return;
+
+       if (pin < 16) {
+               offset = GIUPIODL;
+               mask = 1 << pin;
+       } else if (pin < 32) {
+               offset = GIUPIODH;
+               mask = 1 << (pin - 16);
+       } else if (pin < 48) {
+               offset = GIUPODATL;
+               mask = 1 << (pin - 32);
+       } else {
+               offset = GIUPODATH;
+               mask = 1 << (pin - 48);
+       }
+
+       spin_lock_irqsave(&giu_lock, flags);
+
+       reg = giu_read(offset);
+       if (value)
+               reg |= mask;
+       else
+               reg &= ~mask;
+       giu_write(offset, reg);
+
+       spin_unlock_irqrestore(&giu_lock, flags);
+}
+
+
+static int vr41xx_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
+{
+       return giu_set_direction(chip, offset, GPIO_INPUT);
+}
+
+static int vr41xx_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
+                               int value)
+{
+       vr41xx_gpio_set(chip, offset, value);
+
+       return giu_set_direction(chip, offset, GPIO_OUTPUT);
+}
+
+static int vr41xx_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
+{
+       if (offset >= chip->ngpio)
+               return -EINVAL;
+
+       return GIU_IRQ_BASE + offset;
+}
+
+static struct gpio_chip vr41xx_gpio_chip = {
+       .label                  = "vr41xx",
+       .owner                  = THIS_MODULE,
+       .direction_input        = vr41xx_gpio_direction_input,
+       .get                    = vr41xx_gpio_get,
+       .direction_output       = vr41xx_gpio_direction_output,
+       .set                    = vr41xx_gpio_set,
+       .to_irq                 = vr41xx_gpio_to_irq,
+};
+
+static int __devinit giu_probe(struct platform_device *pdev)
+{
+       struct resource *res;
+       unsigned int trigger, i, pin;
+       struct irq_chip *chip;
+       int irq, retval;
+
+       switch (pdev->id) {
+       case GPIO_50PINS_PULLUPDOWN:
+               giu_flags = GPIO_HAS_PULLUPDOWN_IO;
+               vr41xx_gpio_chip.ngpio = 50;
+               break;
+       case GPIO_36PINS:
+               vr41xx_gpio_chip.ngpio = 36;
+               break;
+       case GPIO_48PINS_EDGE_SELECT:
+               giu_flags = GPIO_HAS_INTERRUPT_EDGE_SELECT;
+               vr41xx_gpio_chip.ngpio = 48;
+               break;
+       default:
+               dev_err(&pdev->dev, "GIU: unknown ID %d\n", pdev->id);
+               return -ENODEV;
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res)
+               return -EBUSY;
+
+       giu_base = ioremap(res->start, res->end - res->start + 1);
+       if (!giu_base)
+               return -ENOMEM;
+
+       vr41xx_gpio_chip.dev = &pdev->dev;
+
+       retval = gpiochip_add(&vr41xx_gpio_chip);
+
+       giu_write(GIUINTENL, 0);
+       giu_write(GIUINTENH, 0);
+
+       trigger = giu_read(GIUINTTYPH) << 16;
+       trigger |= giu_read(GIUINTTYPL);
+       for (i = GIU_IRQ_BASE; i <= GIU_IRQ_LAST; i++) {
+               pin = GPIO_PIN_OF_IRQ(i);
+               if (pin < GIUINT_HIGH_OFFSET)
+                       chip = &giuint_low_irq_chip;
+               else
+                       chip = &giuint_high_irq_chip;
+
+               if (trigger & (1 << pin))
+                       set_irq_chip_and_handler(i, chip, handle_edge_irq);
+               else
+                       set_irq_chip_and_handler(i, chip, handle_level_irq);
+
+       }
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0 || irq >= nr_irqs)
+               return -EBUSY;
+
+       return cascade_irq(irq, giu_get_irq);
+}
+
+static int __devexit giu_remove(struct platform_device *pdev)
+{
+       if (giu_base) {
+               iounmap(giu_base);
+               giu_base = NULL;
+       }
+
+       return 0;
+}
+
+static struct platform_driver giu_device_driver = {
+       .probe          = giu_probe,
+       .remove         = __devexit_p(giu_remove),
+       .driver         = {
+               .name   = "GIU",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init vr41xx_giu_init(void)
+{
+       return platform_driver_register(&giu_device_driver);
+}
+
+static void __exit vr41xx_giu_exit(void)
+{
+       platform_driver_unregister(&giu_device_driver);
+}
+
+module_init(vr41xx_giu_init);
+module_exit(vr41xx_giu_exit);
index c961fe4..39b393d 100644 (file)
@@ -81,6 +81,7 @@ config DRM_I830
 
 config DRM_I915
        tristate "i915 driver"
+       depends on AGP_INTEL
        select FB_CFB_FILLRECT
        select FB_CFB_COPYAREA
        select FB_CFB_IMAGEBLIT
index 4e89ab0..fe23f29 100644 (file)
@@ -16,6 +16,7 @@ drm-y       :=        drm_auth.o drm_bufs.o drm_cache.o \
 drm-$(CONFIG_COMPAT) += drm_ioc32.o
 
 obj-$(CONFIG_DRM)      += drm.o
+obj-$(CONFIG_DRM_TTM)  += ttm/
 obj-$(CONFIG_DRM_TDFX) += tdfx/
 obj-$(CONFIG_DRM_R128) += r128/
 obj-$(CONFIG_DRM_RADEON)+= radeon/
@@ -26,4 +27,3 @@ obj-$(CONFIG_DRM_I915)  += i915/
 obj-$(CONFIG_DRM_SIS)   += sis/
 obj-$(CONFIG_DRM_SAVAGE)+= savage/
 obj-$(CONFIG_DRM_VIA)  +=via/
-obj-$(CONFIG_DRM_TTM)  += ttm/
index 7d08352..80cc6d0 100644 (file)
@@ -294,10 +294,10 @@ static struct drm_display_mode *drm_mode_detailed(struct drm_device *dev,
        unsigned vactive = (pt->vactive_vblank_hi & 0xf0) << 4 | pt->vactive_lo;
        unsigned hblank = (pt->hactive_hblank_hi & 0xf) << 8 | pt->hblank_lo;
        unsigned vblank = (pt->vactive_vblank_hi & 0xf) << 8 | pt->vblank_lo;
-       unsigned hsync_offset = (pt->hsync_vsync_offset_pulse_width_hi & 0x3) << 8 | pt->hsync_offset_lo;
-       unsigned hsync_pulse_width = (pt->hsync_vsync_offset_pulse_width_hi & 0xc) << 6 | pt->hsync_pulse_width_lo;
-       unsigned vsync_offset = (pt->hsync_vsync_offset_pulse_width_hi & 0x30) | (pt->vsync_offset_pulse_width_lo & 0xf);
-       unsigned vsync_pulse_width = (pt->hsync_vsync_offset_pulse_width_hi & 0xc0) >> 2 | pt->vsync_offset_pulse_width_lo >> 4;
+       unsigned hsync_offset = (pt->hsync_vsync_offset_pulse_width_hi & 0xc0) << 2 | pt->hsync_offset_lo;
+       unsigned hsync_pulse_width = (pt->hsync_vsync_offset_pulse_width_hi & 0x30) << 4 | pt->hsync_pulse_width_lo;
+       unsigned vsync_offset = (pt->hsync_vsync_offset_pulse_width_hi & 0xc) >> 2 | pt->vsync_offset_pulse_width_lo >> 4;
+       unsigned vsync_pulse_width = (pt->hsync_vsync_offset_pulse_width_hi & 0x3) << 4 | (pt->vsync_offset_pulse_width_lo & 0xf);
 
        /* ignore tiny modes */
        if (hactive < 64 || vactive < 64)
@@ -347,8 +347,8 @@ static struct drm_display_mode *drm_mode_detailed(struct drm_device *dev,
        mode->flags |= (pt->misc & DRM_EDID_PT_VSYNC_POSITIVE) ?
                DRM_MODE_FLAG_PVSYNC : DRM_MODE_FLAG_NVSYNC;
 
-       mode->width_mm = pt->width_mm_lo | (pt->width_height_mm_hi & 0xf) << 8;
-       mode->height_mm = pt->height_mm_lo | (pt->width_height_mm_hi & 0xf0) << 4;
+       mode->width_mm = pt->width_mm_lo | (pt->width_height_mm_hi & 0xf0) << 4;
+       mode->height_mm = pt->height_mm_lo | (pt->width_height_mm_hi & 0xf) << 8;
 
        if (quirks & EDID_QUIRK_DETAILED_IN_CM) {
                mode->width_mm *= 10;
index 51c5a05..30d6b99 100644 (file)
@@ -13,6 +13,8 @@ i915-y := i915_drv.o i915_dma.o i915_irq.o i915_mem.o \
          intel_crt.o \
          intel_lvds.o \
          intel_bios.o \
+         intel_dp.o \
+         intel_dp_i2c.o \
          intel_hdmi.o \
          intel_sdvo.o \
          intel_modes.o \
index e747ac4..288fc50 100644 (file)
@@ -37,7 +37,7 @@ struct intel_dvo_device {
        /* GPIO register used for i2c bus to control this device */
        u32 gpio;
        int slave_addr;
-       struct intel_i2c_chan *i2c_bus;
+       struct i2c_adapter *i2c_bus;
 
        const struct intel_dvo_dev_ops *dev_ops;
        void *dev_priv;
@@ -52,7 +52,7 @@ struct intel_dvo_dev_ops {
         * Returns NULL if the device does not exist.
         */
        bool (*init)(struct intel_dvo_device *dvo,
-                    struct intel_i2c_chan *i2cbus);
+                    struct i2c_adapter *i2cbus);
 
        /*
         * Called to allow the output a chance to create properties after the
index 03d4b49..621815b 100644 (file)
@@ -176,19 +176,20 @@ static void ch7017_dpms(struct intel_dvo_device *dvo, int mode);
 
 static bool ch7017_read(struct intel_dvo_device *dvo, int addr, uint8_t *val)
 {
-       struct intel_i2c_chan *i2cbus = dvo->i2c_bus;
+       struct i2c_adapter *adapter = dvo->i2c_bus;
+       struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter);
        u8 out_buf[2];
        u8 in_buf[2];
 
        struct i2c_msg msgs[] = {
                {
-                       .addr = i2cbus->slave_addr,
+                       .addr = dvo->slave_addr,
                        .flags = 0,
                        .len = 1,
                        .buf = out_buf,
                },
                {
-                       .addr = i2cbus->slave_addr,
+                       .addr = dvo->slave_addr,
                        .flags = I2C_M_RD,
                        .len = 1,
                        .buf = in_buf,
@@ -208,10 +209,11 @@ static bool ch7017_read(struct intel_dvo_device *dvo, int addr, uint8_t *val)
 
 static bool ch7017_write(struct intel_dvo_device *dvo, int addr, uint8_t val)
 {
-       struct intel_i2c_chan *i2cbus = dvo->i2c_bus;
+       struct i2c_adapter *adapter = dvo->i2c_bus;
+       struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter);
        uint8_t out_buf[2];
        struct i2c_msg msg = {
-               .addr = i2cbus->slave_addr,
+               .addr = dvo->slave_addr,
                .flags = 0,
                .len = 2,
                .buf = out_buf,
@@ -228,8 +230,9 @@ static bool ch7017_write(struct intel_dvo_device *dvo, int addr, uint8_t val)
 
 /** Probes for a CH7017 on the given bus and slave address. */
 static bool ch7017_init(struct intel_dvo_device *dvo,
-                       struct intel_i2c_chan *i2cbus)
+                       struct i2c_adapter *adapter)
 {
+       struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter);
        struct ch7017_priv *priv;
        uint8_t val;
 
@@ -237,8 +240,7 @@ static bool ch7017_init(struct intel_dvo_device *dvo,
        if (priv == NULL)
                return false;
 
-       dvo->i2c_bus = i2cbus;
-       dvo->i2c_bus->slave_addr = dvo->slave_addr;
+       dvo->i2c_bus = adapter;
        dvo->dev_priv = priv;
 
        if (!ch7017_read(dvo, CH7017_DEVICE_ID, &val))
@@ -248,7 +250,7 @@ static bool ch7017_init(struct intel_dvo_device *dvo,
            val != CH7018_DEVICE_ID_VALUE &&
            val != CH7019_DEVICE_ID_VALUE) {
                DRM_DEBUG("ch701x not detected, got %d: from %s Slave %d.\n",
-                         val, i2cbus->adapter.name,i2cbus->slave_addr);
+                         val, i2cbus->adapter.name,dvo->slave_addr);
                goto fail;
        }
 
index d2fd95d..a9b8962 100644 (file)
@@ -123,19 +123,20 @@ static char *ch7xxx_get_id(uint8_t vid)
 static bool ch7xxx_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch)
 {
        struct ch7xxx_priv *ch7xxx= dvo->dev_priv;
-       struct intel_i2c_chan *i2cbus = dvo->i2c_bus;
+       struct i2c_adapter *adapter = dvo->i2c_bus;
+       struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter);
        u8 out_buf[2];
        u8 in_buf[2];
 
        struct i2c_msg msgs[] = {
                {
-                       .addr = i2cbus->slave_addr,
+                       .addr = dvo->slave_addr,
                        .flags = 0,
                        .len = 1,
                        .buf = out_buf,
                },
                {
-                       .addr = i2cbus->slave_addr,
+                       .addr = dvo->slave_addr,
                        .flags = I2C_M_RD,
                        .len = 1,
                        .buf = in_buf,
@@ -152,7 +153,7 @@ static bool ch7xxx_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch)
 
        if (!ch7xxx->quiet) {
                DRM_DEBUG("Unable to read register 0x%02x from %s:%02x.\n",
-                         addr, i2cbus->adapter.name, i2cbus->slave_addr);
+                         addr, i2cbus->adapter.name, dvo->slave_addr);
        }
        return false;
 }
@@ -161,10 +162,11 @@ static bool ch7xxx_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch)
 static bool ch7xxx_writeb(struct intel_dvo_device *dvo, int addr, uint8_t ch)
 {
        struct ch7xxx_priv *ch7xxx = dvo->dev_priv;
-       struct intel_i2c_chan *i2cbus = dvo->i2c_bus;
+       struct i2c_adapter *adapter = dvo->i2c_bus;
+       struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter);
        uint8_t out_buf[2];
        struct i2c_msg msg = {
-               .addr = i2cbus->slave_addr,
+               .addr = dvo->slave_addr,
                .flags = 0,
                .len = 2,
                .buf = out_buf,
@@ -178,14 +180,14 @@ static bool ch7xxx_writeb(struct intel_dvo_device *dvo, int addr, uint8_t ch)
 
        if (!ch7xxx->quiet) {
                DRM_DEBUG("Unable to write register 0x%02x to %s:%d.\n",
-                         addr, i2cbus->adapter.name, i2cbus->slave_addr);
+                         addr, i2cbus->adapter.name, dvo->slave_addr);
        }
 
        return false;
 }
 
 static bool ch7xxx_init(struct intel_dvo_device *dvo,
-                       struct intel_i2c_chan *i2cbus)
+                       struct i2c_adapter *adapter)
 {
        /* this will detect the CH7xxx chip on the specified i2c bus */
        struct ch7xxx_priv *ch7xxx;
@@ -196,8 +198,7 @@ static bool ch7xxx_init(struct intel_dvo_device *dvo,
        if (ch7xxx == NULL)
                return false;
 
-       dvo->i2c_bus = i2cbus;
-       dvo->i2c_bus->slave_addr = dvo->slave_addr;
+       dvo->i2c_bus = adapter;
        dvo->dev_priv = ch7xxx;
        ch7xxx->quiet = true;
 
@@ -207,7 +208,7 @@ static bool ch7xxx_init(struct intel_dvo_device *dvo,
        name = ch7xxx_get_id(vendor);
        if (!name) {
                DRM_DEBUG("ch7xxx not detected; got 0x%02x from %s slave %d.\n",
-                         vendor, i2cbus->adapter.name, i2cbus->slave_addr);
+                         vendor, adapter->name, dvo->slave_addr);
                goto out;
        }
 
@@ -217,7 +218,7 @@ static bool ch7xxx_init(struct intel_dvo_device *dvo,
 
        if (device != CH7xxx_DID) {
                DRM_DEBUG("ch7xxx not detected; got 0x%02x from %s slave %d.\n",
-                         vendor, i2cbus->adapter.name, i2cbus->slave_addr);
+                         vendor, adapter->name, dvo->slave_addr);
                goto out;
        }
 
index 0c8d375..aa176f9 100644 (file)
@@ -169,13 +169,14 @@ static void ivch_dump_regs(struct intel_dvo_device *dvo);
 static bool ivch_read(struct intel_dvo_device *dvo, int addr, uint16_t *data)
 {
        struct ivch_priv *priv = dvo->dev_priv;
-       struct intel_i2c_chan *i2cbus = dvo->i2c_bus;
+       struct i2c_adapter *adapter = dvo->i2c_bus;
+       struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter);
        u8 out_buf[1];
        u8 in_buf[2];
 
        struct i2c_msg msgs[] = {
                {
-                       .addr = i2cbus->slave_addr,
+                       .addr = dvo->slave_addr,
                        .flags = I2C_M_RD,
                        .len = 0,
                },
@@ -186,7 +187,7 @@ static bool ivch_read(struct intel_dvo_device *dvo, int addr, uint16_t *data)
                        .buf = out_buf,
                },
                {
-                       .addr = i2cbus->slave_addr,
+                       .addr = dvo->slave_addr,
                        .flags = I2C_M_RD | I2C_M_NOSTART,
                        .len = 2,
                        .buf = in_buf,
@@ -202,7 +203,7 @@ static bool ivch_read(struct intel_dvo_device *dvo, int addr, uint16_t *data)
 
        if (!priv->quiet) {
                DRM_DEBUG("Unable to read register 0x%02x from %s:%02x.\n",
-                         addr, i2cbus->adapter.name, i2cbus->slave_addr);
+                         addr, i2cbus->adapter.name, dvo->slave_addr);
        }
        return false;
 }
@@ -211,10 +212,11 @@ static bool ivch_read(struct intel_dvo_device *dvo, int addr, uint16_t *data)
 static bool ivch_write(struct intel_dvo_device *dvo, int addr, uint16_t data)
 {
        struct ivch_priv *priv = dvo->dev_priv;
-       struct intel_i2c_chan *i2cbus = dvo->i2c_bus;
+       struct i2c_adapter *adapter = dvo->i2c_bus;
+       struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter);
        u8 out_buf[3];
        struct i2c_msg msg = {
-               .addr = i2cbus->slave_addr,
+               .addr = dvo->slave_addr,
                .flags = 0,
                .len = 3,
                .buf = out_buf,
@@ -229,7 +231,7 @@ static bool ivch_write(struct intel_dvo_device *dvo, int addr, uint16_t data)
 
        if (!priv->quiet) {
                DRM_DEBUG("Unable to write register 0x%02x to %s:%d.\n",
-                         addr, i2cbus->adapter.name, i2cbus->slave_addr);
+                         addr, i2cbus->adapter.name, dvo->slave_addr);
        }
 
        return false;
@@ -237,7 +239,7 @@ static bool ivch_write(struct intel_dvo_device *dvo, int addr, uint16_t data)
 
 /** Probes the given bus and slave address for an ivch */
 static bool ivch_init(struct intel_dvo_device *dvo,
-                     struct intel_i2c_chan *i2cbus)
+                     struct i2c_adapter *adapter)
 {
        struct ivch_priv *priv;
        uint16_t temp;
@@ -246,8 +248,7 @@ static bool ivch_init(struct intel_dvo_device *dvo,
        if (priv == NULL)
                return false;
 
-       dvo->i2c_bus = i2cbus;
-       dvo->i2c_bus->slave_addr = dvo->slave_addr;
+       dvo->i2c_bus = adapter;
        dvo->dev_priv = priv;
        priv->quiet = true;
 
index 033a4bb..e1c1f73 100644 (file)
@@ -76,19 +76,20 @@ struct sil164_priv {
 static bool sil164_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch)
 {
        struct sil164_priv *sil = dvo->dev_priv;
-       struct intel_i2c_chan *i2cbus = dvo->i2c_bus;
+       struct i2c_adapter *adapter = dvo->i2c_bus;
+       struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter);
        u8 out_buf[2];
        u8 in_buf[2];
 
        struct i2c_msg msgs[] = {
                {
-                       .addr = i2cbus->slave_addr,
+                       .addr = dvo->slave_addr,
                        .flags = 0,
                        .len = 1,
                        .buf = out_buf,
                },
                {
-                       .addr = i2cbus->slave_addr,
+                       .addr = dvo->slave_addr,
                        .flags = I2C_M_RD,
                        .len = 1,
                        .buf = in_buf,
@@ -105,7 +106,7 @@ static bool sil164_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch)
 
        if (!sil->quiet) {
                DRM_DEBUG("Unable to read register 0x%02x from %s:%02x.\n",
-                         addr, i2cbus->adapter.name, i2cbus->slave_addr);
+                         addr, i2cbus->adapter.name, dvo->slave_addr);
        }
        return false;
 }
@@ -113,10 +114,11 @@ static bool sil164_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch)
 static bool sil164_writeb(struct intel_dvo_device *dvo, int addr, uint8_t ch)
 {
        struct sil164_priv *sil= dvo->dev_priv;
-       struct intel_i2c_chan *i2cbus = dvo->i2c_bus;
+       struct i2c_adapter *adapter = dvo->i2c_bus;
+       struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter);
        uint8_t out_buf[2];
        struct i2c_msg msg = {
-               .addr = i2cbus->slave_addr,
+               .addr = dvo->slave_addr,
                .flags = 0,
                .len = 2,
                .buf = out_buf,
@@ -130,7 +132,7 @@ static bool sil164_writeb(struct intel_dvo_device *dvo, int addr, uint8_t ch)
 
        if (!sil->quiet) {
                DRM_DEBUG("Unable to write register 0x%02x to %s:%d.\n",
-                         addr, i2cbus->adapter.name, i2cbus->slave_addr);
+                         addr, i2cbus->adapter.name, dvo->slave_addr);
        }
 
        return false;
@@ -138,7 +140,7 @@ static bool sil164_writeb(struct intel_dvo_device *dvo, int addr, uint8_t ch)
 
 /* Silicon Image 164 driver for chip on i2c bus */
 static bool sil164_init(struct intel_dvo_device *dvo,
-                       struct intel_i2c_chan *i2cbus)
+                       struct i2c_adapter *adapter)
 {
        /* this will detect the SIL164 chip on the specified i2c bus */
        struct sil164_priv *sil;
@@ -148,8 +150,7 @@ static bool sil164_init(struct intel_dvo_device *dvo,
        if (sil == NULL)
                return false;
 
-       dvo->i2c_bus = i2cbus;
-       dvo->i2c_bus->slave_addr = dvo->slave_addr;
+       dvo->i2c_bus = adapter;
        dvo->dev_priv = sil;
        sil->quiet = true;
 
@@ -158,7 +159,7 @@ static bool sil164_init(struct intel_dvo_device *dvo,
 
        if (ch != (SIL164_VID & 0xff)) {
                DRM_DEBUG("sil164 not detected got %d: from %s Slave %d.\n",
-                         ch, i2cbus->adapter.name, i2cbus->slave_addr);
+                         ch, adapter->name, dvo->slave_addr);
                goto out;
        }
 
@@ -167,7 +168,7 @@ static bool sil164_init(struct intel_dvo_device *dvo,
 
        if (ch != (SIL164_DID & 0xff)) {
                DRM_DEBUG("sil164 not detected got %d: from %s Slave %d.\n",
-                         ch, i2cbus->adapter.name, i2cbus->slave_addr);
+                         ch, adapter->name, dvo->slave_addr);
                goto out;
        }
        sil->quiet = false;
index 207fda8..9ecc907 100644 (file)
@@ -101,19 +101,20 @@ struct tfp410_priv {
 static bool tfp410_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch)
 {
        struct tfp410_priv *tfp = dvo->dev_priv;
-       struct intel_i2c_chan *i2cbus = dvo->i2c_bus;
+       struct i2c_adapter *adapter = dvo->i2c_bus;
+       struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter);
        u8 out_buf[2];
        u8 in_buf[2];
 
        struct i2c_msg msgs[] = {
                {
-                       .addr = i2cbus->slave_addr,
+                       .addr = dvo->slave_addr,
                        .flags = 0,
                        .len = 1,
                        .buf = out_buf,
                },
                {
-                       .addr = i2cbus->slave_addr,
+                       .addr = dvo->slave_addr,
                        .flags = I2C_M_RD,
                        .len = 1,
                        .buf = in_buf,
@@ -130,7 +131,7 @@ static bool tfp410_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch)
 
        if (!tfp->quiet) {
                DRM_DEBUG("Unable to read register 0x%02x from %s:%02x.\n",
-                         addr, i2cbus->adapter.name, i2cbus->slave_addr);
+                         addr, i2cbus->adapter.name, dvo->slave_addr);
        }
        return false;
 }
@@ -138,10 +139,11 @@ static bool tfp410_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch)
 static bool tfp410_writeb(struct intel_dvo_device *dvo, int addr, uint8_t ch)
 {
        struct tfp410_priv *tfp = dvo->dev_priv;
-       struct intel_i2c_chan *i2cbus = dvo->i2c_bus;
+       struct i2c_adapter *adapter = dvo->i2c_bus;
+       struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter);
        uint8_t out_buf[2];
        struct i2c_msg msg = {
-               .addr = i2cbus->slave_addr,
+               .addr = dvo->slave_addr,
                .flags = 0,
                .len = 2,
                .buf = out_buf,
@@ -155,7 +157,7 @@ static bool tfp410_writeb(struct intel_dvo_device *dvo, int addr, uint8_t ch)
 
        if (!tfp->quiet) {
                DRM_DEBUG("Unable to write register 0x%02x to %s:%d.\n",
-                         addr, i2cbus->adapter.name, i2cbus->slave_addr);
+                         addr, i2cbus->adapter.name, dvo->slave_addr);
        }
 
        return false;
@@ -174,7 +176,7 @@ static int tfp410_getid(struct intel_dvo_device *dvo, int addr)
 
 /* Ti TFP410 driver for chip on i2c bus */
 static bool tfp410_init(struct intel_dvo_device *dvo,
-                       struct intel_i2c_chan *i2cbus)
+                       struct i2c_adapter *adapter)
 {
        /* this will detect the tfp410 chip on the specified i2c bus */
        struct tfp410_priv *tfp;
@@ -184,20 +186,19 @@ static bool tfp410_init(struct intel_dvo_device *dvo,
        if (tfp == NULL)
                return false;
 
-       dvo->i2c_bus = i2cbus;
-       dvo->i2c_bus->slave_addr = dvo->slave_addr;
+       dvo->i2c_bus = adapter;
        dvo->dev_priv = tfp;
        tfp->quiet = true;
 
        if ((id = tfp410_getid(dvo, TFP410_VID_LO)) != TFP410_VID) {
                DRM_DEBUG("tfp410 not detected got VID %X: from %s Slave %d.\n",
-                         id, i2cbus->adapter.name, i2cbus->slave_addr);
+                         id, adapter->name, dvo->slave_addr);
                goto out;
        }
 
        if ((id = tfp410_getid(dvo, TFP410_DID_LO)) != TFP410_DID) {
                DRM_DEBUG("tfp410 not detected got DID %X: from %s Slave %d.\n",
-                         id, i2cbus->adapter.name, i2cbus->slave_addr);
+                         id, adapter->name, dvo->slave_addr);
                goto out;
        }
        tfp->quiet = false;
index 98560e1..e3cb402 100644 (file)
@@ -67,8 +67,6 @@ static int i915_suspend(struct drm_device *dev, pm_message_t state)
 
        pci_save_state(dev->pdev);
 
-       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))
@@ -77,6 +75,8 @@ static int i915_suspend(struct drm_device *dev, pm_message_t state)
                drm_irq_uninstall(dev);
        }
 
+       i915_save_state(dev);
+
        intel_opregion_free(dev, 1);
 
        if (state.event == PM_EVENT_SUSPEND) {
index 7a84f04..bb4c2d3 100644 (file)
@@ -306,6 +306,17 @@ typedef struct drm_i915_private {
        u32 saveCURBPOS;
        u32 saveCURBBASE;
        u32 saveCURSIZE;
+       u32 saveDP_B;
+       u32 saveDP_C;
+       u32 saveDP_D;
+       u32 savePIPEA_GMCH_DATA_M;
+       u32 savePIPEB_GMCH_DATA_M;
+       u32 savePIPEA_GMCH_DATA_N;
+       u32 savePIPEB_GMCH_DATA_N;
+       u32 savePIPEA_DP_LINK_M;
+       u32 savePIPEB_DP_LINK_M;
+       u32 savePIPEA_DP_LINK_N;
+       u32 savePIPEB_DP_LINK_N;
 
        struct {
                struct drm_mm gtt_space;
@@ -857,6 +868,7 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller);
 #define HAS_128_BYTE_Y_TILING(dev) (IS_I9XX(dev) && !(IS_I915G(dev) || \
                                                      IS_I915GM(dev)))
 #define SUPPORTS_INTEGRATED_HDMI(dev)  (IS_G4X(dev) || IS_IGDNG(dev))
+#define SUPPORTS_INTEGRATED_DP(dev)    (IS_G4X(dev) || IS_IGDNG(dev))
 #define I915_HAS_HOTPLUG(dev) (IS_I945G(dev) || IS_I945GM(dev) || IS_I965G(dev))
 
 #define PRIMARY_RINGBUFFER_SIZE         (128*1024)
index fd2b8bd..876b65c 100644 (file)
@@ -1006,7 +1006,7 @@ i915_gem_set_domain_ioctl(struct drm_device *dev, void *data,
 
        mutex_lock(&dev->struct_mutex);
 #if WATCH_BUF
-       DRM_INFO("set_domain_ioctl %p(%d), %08x %08x\n",
+       DRM_INFO("set_domain_ioctl %p(%zd), %08x %08x\n",
                 obj, obj->size, read_domains, write_domain);
 #endif
        if (read_domains & I915_GEM_DOMAIN_GTT) {
@@ -1050,7 +1050,7 @@ i915_gem_sw_finish_ioctl(struct drm_device *dev, void *data,
        }
 
 #if WATCH_BUF
-       DRM_INFO("%s: sw_finish %d (%p %d)\n",
+       DRM_INFO("%s: sw_finish %d (%p %zd)\n",
                 __func__, args->handle, obj, obj->size);
 #endif
        obj_priv = obj->driver_private;
@@ -2423,7 +2423,7 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment)
        }
 
 #if WATCH_BUF
-       DRM_INFO("Binding object of size %d at 0x%08x\n",
+       DRM_INFO("Binding object of size %zd at 0x%08x\n",
                 obj->size, obj_priv->gtt_offset);
 #endif
        ret = i915_gem_object_get_pages(obj);
@@ -4227,6 +4227,7 @@ i915_gem_lastclose(struct drm_device *dev)
 void
 i915_gem_load(struct drm_device *dev)
 {
+       int i;
        drm_i915_private_t *dev_priv = dev->dev_private;
 
        spin_lock_init(&dev_priv->mm.active_list_lock);
@@ -4246,6 +4247,18 @@ i915_gem_load(struct drm_device *dev)
        else
                dev_priv->num_fence_regs = 8;
 
+       /* Initialize fence registers to zero */
+       if (IS_I965G(dev)) {
+               for (i = 0; i < 16; i++)
+                       I915_WRITE64(FENCE_REG_965_0 + (i * 8), 0);
+       } else {
+               for (i = 0; i < 8; i++)
+                       I915_WRITE(FENCE_REG_830_0 + (i * 4), 0);
+               if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev))
+                       for (i = 0; i < 8; i++)
+                               I915_WRITE(FENCE_REG_945_8 + (i * 4), 0);
+       }
+
        i915_gem_detect_bit_6_swizzle(dev);
 }
 
index 8d0b943..e602614 100644 (file)
@@ -87,7 +87,7 @@ i915_gem_dump_object(struct drm_gem_object *obj, int len,
                        chunk_len = page_len - chunk;
                        if (chunk_len > 128)
                                chunk_len = 128;
-                       i915_gem_dump_page(obj_priv->page_list[page],
+                       i915_gem_dump_page(obj_priv->pages[page],
                                           chunk, chunk + chunk_len,
                                           obj_priv->gtt_offset +
                                           page * PAGE_SIZE,
@@ -143,7 +143,7 @@ i915_gem_object_check_coherency(struct drm_gem_object *obj, int handle)
        uint32_t *backing_map = NULL;
        int bad_count = 0;
 
-       DRM_INFO("%s: checking coherency of object %p@0x%08x (%d, %dkb):\n",
+       DRM_INFO("%s: checking coherency of object %p@0x%08x (%d, %zdkb):\n",
                 __func__, obj, obj_priv->gtt_offset, handle,
                 obj->size / 1024);
 
@@ -157,7 +157,7 @@ i915_gem_object_check_coherency(struct drm_gem_object *obj, int handle)
        for (page = 0; page < obj->size / PAGE_SIZE; page++) {
                int i;
 
-               backing_map = kmap_atomic(obj_priv->page_list[page], KM_USER0);
+               backing_map = kmap_atomic(obj_priv->pages[page], KM_USER0);
 
                if (backing_map == NULL) {
                        DRM_ERROR("failed to map backing page\n");
index 5c1ceec..daeae62 100644 (file)
@@ -114,11 +114,13 @@ intel_alloc_mchbar_resource(struct drm_device *dev)
        mchbar_addr = ((u64)temp_hi << 32) | temp_lo;
 
        /* If ACPI doesn't have it, assume we need to allocate it ourselves */
+#ifdef CONFIG_PNP
        if (mchbar_addr &&
            pnp_range_reserved(mchbar_addr, mchbar_addr + MCHBAR_SIZE)) {
                ret = 0;
                goto out_put;
        }
+#endif
 
        /* Get some space for it */
        ret = pci_bus_alloc_resource(bridge_dev->bus, &dev_priv->mch_res,
index b86b7b7..228546f 100644 (file)
@@ -232,7 +232,17 @@ static void i915_hotplug_work_func(struct work_struct *work)
        drm_i915_private_t *dev_priv = container_of(work, drm_i915_private_t,
                                                    hotplug_work);
        struct drm_device *dev = dev_priv->dev;
-
+       struct drm_mode_config *mode_config = &dev->mode_config;
+       struct drm_connector *connector;
+
+       if (mode_config->num_connector) {
+               list_for_each_entry(connector, &mode_config->connector_list, head) {
+                       struct intel_output *intel_output = to_intel_output(connector);
+       
+                       if (intel_output->hot_plug)
+                               (*intel_output->hot_plug) (intel_output);
+               }
+       }
        /* Just fire off a uevent and let userspace tell us what to do */
        drm_sysfs_hotplug_event(dev);
 }
index f6237a0..88bf752 100644 (file)
 #define C0DRB3                 0x10206
 #define C1DRB3                 0x10606
 
+/* Clocking configuration register */
+#define CLKCFG                 0x10c00
+#define CLKCFG_FSB_400                                 (0 << 0)        /* hrawclk 100 */
+#define CLKCFG_FSB_533                                 (1 << 0)        /* hrawclk 133 */
+#define CLKCFG_FSB_667                                 (3 << 0)        /* hrawclk 166 */
+#define CLKCFG_FSB_800                                 (2 << 0)        /* hrawclk 200 */
+#define CLKCFG_FSB_1067                                        (6 << 0)        /* hrawclk 266 */
+#define CLKCFG_FSB_1333                                        (7 << 0)        /* hrawclk 333 */
+/* this is a guess, could be 5 as well */
+#define CLKCFG_FSB_1600                                        (4 << 0)        /* hrawclk 400 */
+#define CLKCFG_FSB_1600_ALT                            (5 << 0)        /* hrawclk 400 */
+#define CLKCFG_FSB_MASK                                        (7 << 0)
 /** GM965 GM45 render standby register */
 #define MCHBAR_RENDER_STANDBY  0x111B8
 
 #define   HORIZ_INTERP_MASK    (3 << 6)
 #define   HORIZ_AUTO_SCALE     (1 << 5)
 #define   PANEL_8TO6_DITHER_ENABLE (1 << 3)
+#define   PFIT_FILTER_FUZZY    (0 << 24)
+#define   PFIT_SCALING_AUTO    (0 << 26)
+#define   PFIT_SCALING_PROGRAMMED (1 << 26)
+#define   PFIT_SCALING_PILLAR  (2 << 26)
+#define   PFIT_SCALING_LETTER  (3 << 26)
 #define PFIT_PGM_RATIOS        0x61234
 #define   PFIT_VERT_SCALE_MASK                 0xfff00000
 #define   PFIT_HORIZ_SCALE_MASK                        0x0000fff0
+/* Pre-965 */
+#define                PFIT_VERT_SCALE_SHIFT           20
+#define                PFIT_VERT_SCALE_MASK            0xfff00000
+#define                PFIT_HORIZ_SCALE_SHIFT          4
+#define                PFIT_HORIZ_SCALE_MASK           0x0000fff0
+/* 965+ */
+#define                PFIT_VERT_SCALE_SHIFT_965       16
+#define                PFIT_VERT_SCALE_MASK_965        0x1fff0000
+#define                PFIT_HORIZ_SCALE_SHIFT_965      0
+#define                PFIT_HORIZ_SCALE_MASK_965       0x00001fff
+
 #define PFIT_AUTO_RATIOS 0x61238
 
 /* Backlight control */
index a98e283..8d8e083 100644 (file)
@@ -322,6 +322,20 @@ int i915_save_state(struct drm_device *dev)
        dev_priv->savePP_OFF_DELAYS = I915_READ(PP_OFF_DELAYS);
        dev_priv->savePP_DIVISOR = I915_READ(PP_DIVISOR);
 
+       /* Display Port state */
+       if (SUPPORTS_INTEGRATED_DP(dev)) {
+               dev_priv->saveDP_B = I915_READ(DP_B);
+               dev_priv->saveDP_C = I915_READ(DP_C);
+               dev_priv->saveDP_D = I915_READ(DP_D);
+               dev_priv->savePIPEA_GMCH_DATA_M = I915_READ(PIPEA_GMCH_DATA_M);
+               dev_priv->savePIPEB_GMCH_DATA_M = I915_READ(PIPEB_GMCH_DATA_M);
+               dev_priv->savePIPEA_GMCH_DATA_N = I915_READ(PIPEA_GMCH_DATA_N);
+               dev_priv->savePIPEB_GMCH_DATA_N = I915_READ(PIPEB_GMCH_DATA_N);
+               dev_priv->savePIPEA_DP_LINK_M = I915_READ(PIPEA_DP_LINK_M);
+               dev_priv->savePIPEB_DP_LINK_M = I915_READ(PIPEB_DP_LINK_M);
+               dev_priv->savePIPEA_DP_LINK_N = I915_READ(PIPEA_DP_LINK_N);
+               dev_priv->savePIPEB_DP_LINK_N = I915_READ(PIPEB_DP_LINK_N);
+       }
        /* FIXME: save TV & SDVO state */
 
        /* FBC state */
@@ -404,7 +418,19 @@ int i915_restore_state(struct drm_device *dev)
                        for (i = 0; i < 8; i++)
                                I915_WRITE(FENCE_REG_945_8 + (i * 4), dev_priv->saveFENCE[i+8]);
        }
-
+       
+       /* Display port ratios (must be done before clock is set) */
+       if (SUPPORTS_INTEGRATED_DP(dev)) {
+               I915_WRITE(PIPEA_GMCH_DATA_M, dev_priv->savePIPEA_GMCH_DATA_M);
+               I915_WRITE(PIPEB_GMCH_DATA_M, dev_priv->savePIPEB_GMCH_DATA_M);
+               I915_WRITE(PIPEA_GMCH_DATA_N, dev_priv->savePIPEA_GMCH_DATA_N);
+               I915_WRITE(PIPEB_GMCH_DATA_N, dev_priv->savePIPEB_GMCH_DATA_N);
+               I915_WRITE(PIPEA_DP_LINK_M, dev_priv->savePIPEA_DP_LINK_M);
+               I915_WRITE(PIPEB_DP_LINK_M, dev_priv->savePIPEB_DP_LINK_M);
+               I915_WRITE(PIPEA_DP_LINK_N, dev_priv->savePIPEA_DP_LINK_N);
+               I915_WRITE(PIPEB_DP_LINK_N, dev_priv->savePIPEB_DP_LINK_N);
+       }
+       
        /* Pipe & plane A info */
        /* Prime the clock */
        if (dev_priv->saveDPLL_A & DPLL_VCO_ENABLE) {
@@ -518,6 +544,12 @@ int i915_restore_state(struct drm_device *dev)
        I915_WRITE(PP_DIVISOR, dev_priv->savePP_DIVISOR);
        I915_WRITE(PP_CONTROL, dev_priv->savePP_CONTROL);
 
+       /* Display Port state */
+       if (SUPPORTS_INTEGRATED_DP(dev)) {
+               I915_WRITE(DP_B, dev_priv->saveDP_B);
+               I915_WRITE(DP_C, dev_priv->saveDP_C);
+               I915_WRITE(DP_D, dev_priv->saveDP_D);
+       }
        /* FIXME: restore TV & SDVO state */
 
        /* FBC info */
index cdd126d..716409a 100644 (file)
@@ -99,9 +99,11 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv,
 {
        struct bdb_lvds_options *lvds_options;
        struct bdb_lvds_lfp_data *lvds_lfp_data;
+       struct bdb_lvds_lfp_data_ptrs *lvds_lfp_data_ptrs;
        struct bdb_lvds_lfp_data_entry *entry;
        struct lvds_dvo_timing *dvo_timing;
        struct drm_display_mode *panel_fixed_mode;
+       int lfp_data_size;
 
        /* Defaults if we can't find VBT info */
        dev_priv->lvds_dither = 0;
@@ -119,9 +121,17 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv,
        if (!lvds_lfp_data)
                return;
 
+       lvds_lfp_data_ptrs = find_section(bdb, BDB_LVDS_LFP_DATA_PTRS);
+       if (!lvds_lfp_data_ptrs)
+               return;
+
        dev_priv->lvds_vbt = 1;
 
-       entry = &lvds_lfp_data->data[lvds_options->panel_type];
+       lfp_data_size = lvds_lfp_data_ptrs->ptr[1].dvo_timing_offset -
+               lvds_lfp_data_ptrs->ptr[0].dvo_timing_offset;
+       entry = (struct bdb_lvds_lfp_data_entry *)
+               ((uint8_t *)lvds_lfp_data->data + (lfp_data_size *
+                                                  lvds_options->panel_type));
        dvo_timing = &entry->dvo_timing;
 
        panel_fixed_mode = kzalloc(sizeof(*panel_fixed_mode), GFP_KERNEL);
index 3e1c781..73e7b9c 100644 (file)
@@ -29,6 +29,7 @@
 #include "intel_drv.h"
 #include "i915_drm.h"
 #include "i915_drv.h"
+#include "intel_dp.h"
 
 #include "drm_crtc_helper.h"
 
@@ -127,19 +128,6 @@ struct intel_limit {
 #define I9XX_P2_LVDS_FAST                    7
 #define I9XX_P2_LVDS_SLOW_LIMIT                 112000
 
-#define INTEL_LIMIT_I8XX_DVO_DAC    0
-#define INTEL_LIMIT_I8XX_LVDS      1
-#define INTEL_LIMIT_I9XX_SDVO_DAC   2
-#define INTEL_LIMIT_I9XX_LVDS      3
-#define INTEL_LIMIT_G4X_SDVO       4
-#define INTEL_LIMIT_G4X_HDMI_DAC   5
-#define INTEL_LIMIT_G4X_SINGLE_CHANNEL_LVDS   6
-#define INTEL_LIMIT_G4X_DUAL_CHANNEL_LVDS   7
-#define INTEL_LIMIT_IGD_SDVO_DAC    8
-#define INTEL_LIMIT_IGD_LVDS       9
-#define INTEL_LIMIT_IGDNG_SDVO_DAC  10
-#define INTEL_LIMIT_IGDNG_LVDS     11
-
 /*The parameter is for SDVO on G4x platform*/
 #define G4X_DOT_SDVO_MIN           25000
 #define G4X_DOT_SDVO_MAX           270000
@@ -218,6 +206,25 @@ struct intel_limit {
 #define G4X_P2_DUAL_CHANNEL_LVDS_FAST           7
 #define G4X_P2_DUAL_CHANNEL_LVDS_LIMIT          0
 
+/*The parameter is for DISPLAY PORT on G4x platform*/
+#define G4X_DOT_DISPLAY_PORT_MIN           161670
+#define G4X_DOT_DISPLAY_PORT_MAX           227000
+#define G4X_N_DISPLAY_PORT_MIN             1
+#define G4X_N_DISPLAY_PORT_MAX             2
+#define G4X_M_DISPLAY_PORT_MIN             97
+#define G4X_M_DISPLAY_PORT_MAX             108
+#define G4X_M1_DISPLAY_PORT_MIN            0x10
+#define G4X_M1_DISPLAY_PORT_MAX            0x12
+#define G4X_M2_DISPLAY_PORT_MIN            0x05
+#define G4X_M2_DISPLAY_PORT_MAX            0x06
+#define G4X_P_DISPLAY_PORT_MIN             10
+#define G4X_P_DISPLAY_PORT_MAX             20
+#define G4X_P1_DISPLAY_PORT_MIN            1
+#define G4X_P1_DISPLAY_PORT_MAX            2
+#define G4X_P2_DISPLAY_PORT_SLOW           10
+#define G4X_P2_DISPLAY_PORT_FAST           10
+#define G4X_P2_DISPLAY_PORT_LIMIT          0
+
 /* IGDNG */
 /* as we calculate clock using (register_value + 2) for
    N/M1/M2, so here the range value for them is (actual_value-2).
@@ -256,8 +263,11 @@ static bool
 intel_igdng_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
                        int target, int refclk, intel_clock_t *best_clock);
 
-static const intel_limit_t intel_limits[] = {
-    { /* INTEL_LIMIT_I8XX_DVO_DAC */
+static bool
+intel_find_pll_g4x_dp(const intel_limit_t *, struct drm_crtc *crtc,
+                     int target, int refclk, intel_clock_t *best_clock);
+
+static const intel_limit_t intel_limits_i8xx_dvo = {
         .dot = { .min = I8XX_DOT_MIN,          .max = I8XX_DOT_MAX },
         .vco = { .min = I8XX_VCO_MIN,          .max = I8XX_VCO_MAX },
         .n   = { .min = I8XX_N_MIN,            .max = I8XX_N_MAX },
@@ -269,8 +279,9 @@ static const intel_limit_t intel_limits[] = {
        .p2  = { .dot_limit = I8XX_P2_SLOW_LIMIT,
                 .p2_slow = I8XX_P2_SLOW,       .p2_fast = I8XX_P2_FAST },
        .find_pll = intel_find_best_PLL,
-    },
-    { /* INTEL_LIMIT_I8XX_LVDS */
+};
+
+static const intel_limit_t intel_limits_i8xx_lvds = {
         .dot = { .min = I8XX_DOT_MIN,          .max = I8XX_DOT_MAX },
         .vco = { .min = I8XX_VCO_MIN,          .max = I8XX_VCO_MAX },
         .n   = { .min = I8XX_N_MIN,            .max = I8XX_N_MAX },
@@ -282,8 +293,9 @@ static const intel_limit_t intel_limits[] = {
        .p2  = { .dot_limit = I8XX_P2_SLOW_LIMIT,
                 .p2_slow = I8XX_P2_LVDS_SLOW,  .p2_fast = I8XX_P2_LVDS_FAST },
        .find_pll = intel_find_best_PLL,
-    },
-    { /* INTEL_LIMIT_I9XX_SDVO_DAC */
+};
+       
+static const intel_limit_t intel_limits_i9xx_sdvo = {
         .dot = { .min = I9XX_DOT_MIN,          .max = I9XX_DOT_MAX },
         .vco = { .min = I9XX_VCO_MIN,          .max = I9XX_VCO_MAX },
         .n   = { .min = I9XX_N_MIN,            .max = I9XX_N_MAX },
@@ -295,8 +307,9 @@ static const intel_limit_t intel_limits[] = {
        .p2  = { .dot_limit = I9XX_P2_SDVO_DAC_SLOW_LIMIT,
                 .p2_slow = I9XX_P2_SDVO_DAC_SLOW,      .p2_fast = I9XX_P2_SDVO_DAC_FAST },
        .find_pll = intel_find_best_PLL,
-    },
-    { /* INTEL_LIMIT_I9XX_LVDS */
+};
+
+static const intel_limit_t intel_limits_i9xx_lvds = {
         .dot = { .min = I9XX_DOT_MIN,          .max = I9XX_DOT_MAX },
         .vco = { .min = I9XX_VCO_MIN,          .max = I9XX_VCO_MAX },
         .n   = { .min = I9XX_N_MIN,            .max = I9XX_N_MAX },
@@ -311,9 +324,10 @@ static const intel_limit_t intel_limits[] = {
        .p2  = { .dot_limit = I9XX_P2_LVDS_SLOW_LIMIT,
                 .p2_slow = I9XX_P2_LVDS_SLOW,  .p2_fast = I9XX_P2_LVDS_FAST },
        .find_pll = intel_find_best_PLL,
-    },
+};
+
     /* below parameter and function is for G4X Chipset Family*/
-    { /* INTEL_LIMIT_G4X_SDVO */
+static const intel_limit_t intel_limits_g4x_sdvo = {
        .dot = { .min = G4X_DOT_SDVO_MIN,       .max = G4X_DOT_SDVO_MAX },
        .vco = { .min = G4X_VCO_MIN,            .max = G4X_VCO_MAX},
        .n   = { .min = G4X_N_SDVO_MIN,         .max = G4X_N_SDVO_MAX },
@@ -327,8 +341,9 @@ static const intel_limit_t intel_limits[] = {
                 .p2_fast = G4X_P2_SDVO_FAST
        },
        .find_pll = intel_g4x_find_best_PLL,
-    },
-    { /* INTEL_LIMIT_G4X_HDMI_DAC */
+};
+
+static const intel_limit_t intel_limits_g4x_hdmi = {
        .dot = { .min = G4X_DOT_HDMI_DAC_MIN,   .max = G4X_DOT_HDMI_DAC_MAX },
        .vco = { .min = G4X_VCO_MIN,            .max = G4X_VCO_MAX},
        .n   = { .min = G4X_N_HDMI_DAC_MIN,     .max = G4X_N_HDMI_DAC_MAX },
@@ -342,8 +357,9 @@ static const intel_limit_t intel_limits[] = {
                 .p2_fast = G4X_P2_HDMI_DAC_FAST
        },
        .find_pll = intel_g4x_find_best_PLL,
-    },
-    { /* INTEL_LIMIT_G4X_SINGLE_CHANNEL_LVDS */
+};
+
+static const intel_limit_t intel_limits_g4x_single_channel_lvds = {
        .dot = { .min = G4X_DOT_SINGLE_CHANNEL_LVDS_MIN,
                 .max = G4X_DOT_SINGLE_CHANNEL_LVDS_MAX },
        .vco = { .min = G4X_VCO_MIN,
@@ -365,8 +381,9 @@ static const intel_limit_t intel_limits[] = {
                 .p2_fast = G4X_P2_SINGLE_CHANNEL_LVDS_FAST
        },
        .find_pll = intel_g4x_find_best_PLL,
-    },
-    { /* INTEL_LIMIT_G4X_DUAL_CHANNEL_LVDS */
+};
+
+static const intel_limit_t intel_limits_g4x_dual_channel_lvds = {
        .dot = { .min = G4X_DOT_DUAL_CHANNEL_LVDS_MIN,
                 .max = G4X_DOT_DUAL_CHANNEL_LVDS_MAX },
        .vco = { .min = G4X_VCO_MIN,
@@ -388,8 +405,32 @@ static const intel_limit_t intel_limits[] = {
                 .p2_fast = G4X_P2_DUAL_CHANNEL_LVDS_FAST
        },
        .find_pll = intel_g4x_find_best_PLL,
-    },
-    { /* INTEL_LIMIT_IGD_SDVO */
+};
+
+static const intel_limit_t intel_limits_g4x_display_port = {
+        .dot = { .min = G4X_DOT_DISPLAY_PORT_MIN,
+                 .max = G4X_DOT_DISPLAY_PORT_MAX },
+        .vco = { .min = G4X_VCO_MIN,
+                 .max = G4X_VCO_MAX},
+        .n   = { .min = G4X_N_DISPLAY_PORT_MIN,
+                 .max = G4X_N_DISPLAY_PORT_MAX },
+        .m   = { .min = G4X_M_DISPLAY_PORT_MIN,
+                 .max = G4X_M_DISPLAY_PORT_MAX },
+        .m1  = { .min = G4X_M1_DISPLAY_PORT_MIN,
+                 .max = G4X_M1_DISPLAY_PORT_MAX },
+        .m2  = { .min = G4X_M2_DISPLAY_PORT_MIN,
+                 .max = G4X_M2_DISPLAY_PORT_MAX },
+        .p   = { .min = G4X_P_DISPLAY_PORT_MIN,
+                 .max = G4X_P_DISPLAY_PORT_MAX },
+        .p1  = { .min = G4X_P1_DISPLAY_PORT_MIN,
+                 .max = G4X_P1_DISPLAY_PORT_MAX},
+        .p2  = { .dot_limit = G4X_P2_DISPLAY_PORT_LIMIT,
+                 .p2_slow = G4X_P2_DISPLAY_PORT_SLOW,
+                 .p2_fast = G4X_P2_DISPLAY_PORT_FAST },
+        .find_pll = intel_find_pll_g4x_dp,
+};
+
+static const intel_limit_t intel_limits_igd_sdvo = {
         .dot = { .min = I9XX_DOT_MIN,          .max = I9XX_DOT_MAX},
         .vco = { .min = IGD_VCO_MIN,           .max = IGD_VCO_MAX },
         .n   = { .min = IGD_N_MIN,             .max = IGD_N_MAX },
@@ -401,8 +442,9 @@ static const intel_limit_t intel_limits[] = {
        .p2  = { .dot_limit = I9XX_P2_SDVO_DAC_SLOW_LIMIT,
                 .p2_slow = I9XX_P2_SDVO_DAC_SLOW,      .p2_fast = I9XX_P2_SDVO_DAC_FAST },
        .find_pll = intel_find_best_PLL,
-    },
-    { /* INTEL_LIMIT_IGD_LVDS */
+};
+
+static const intel_limit_t intel_limits_igd_lvds = {
         .dot = { .min = I9XX_DOT_MIN,          .max = I9XX_DOT_MAX },
         .vco = { .min = IGD_VCO_MIN,           .max = IGD_VCO_MAX },
         .n   = { .min = IGD_N_MIN,             .max = IGD_N_MAX },
@@ -415,8 +457,9 @@ static const intel_limit_t intel_limits[] = {
        .p2  = { .dot_limit = I9XX_P2_LVDS_SLOW_LIMIT,
                 .p2_slow = I9XX_P2_LVDS_SLOW,  .p2_fast = I9XX_P2_LVDS_SLOW },
        .find_pll = intel_find_best_PLL,
-    },
-    { /* INTEL_LIMIT_IGDNG_SDVO_DAC */
+};
+
+static const intel_limit_t intel_limits_igdng_sdvo = {
        .dot = { .min = IGDNG_DOT_MIN,          .max = IGDNG_DOT_MAX },
        .vco = { .min = IGDNG_VCO_MIN,          .max = IGDNG_VCO_MAX },
        .n   = { .min = IGDNG_N_MIN,            .max = IGDNG_N_MAX },
@@ -429,8 +472,9 @@ static const intel_limit_t intel_limits[] = {
                 .p2_slow = IGDNG_P2_SDVO_DAC_SLOW,
                 .p2_fast = IGDNG_P2_SDVO_DAC_FAST },
        .find_pll = intel_igdng_find_best_PLL,
-    },
-    { /* INTEL_LIMIT_IGDNG_LVDS */
+};
+
+static const intel_limit_t intel_limits_igdng_lvds = {
        .dot = { .min = IGDNG_DOT_MIN,          .max = IGDNG_DOT_MAX },
        .vco = { .min = IGDNG_VCO_MIN,          .max = IGDNG_VCO_MAX },
        .n   = { .min = IGDNG_N_MIN,            .max = IGDNG_N_MAX },
@@ -443,16 +487,15 @@ static const intel_limit_t intel_limits[] = {
                 .p2_slow = IGDNG_P2_LVDS_SLOW,
                 .p2_fast = IGDNG_P2_LVDS_FAST },
        .find_pll = intel_igdng_find_best_PLL,
-    },
 };
 
 static const intel_limit_t *intel_igdng_limit(struct drm_crtc *crtc)
 {
        const intel_limit_t *limit;
        if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS))
-               limit = &intel_limits[INTEL_LIMIT_IGDNG_LVDS];
+               limit = &intel_limits_igdng_lvds;
        else
-               limit = &intel_limits[INTEL_LIMIT_IGDNG_SDVO_DAC];
+               limit = &intel_limits_igdng_sdvo;
 
        return limit;
 }
@@ -467,19 +510,19 @@ static const intel_limit_t *intel_g4x_limit(struct drm_crtc *crtc)
                if ((I915_READ(LVDS) & LVDS_CLKB_POWER_MASK) ==
                    LVDS_CLKB_POWER_UP)
                        /* LVDS with dual channel */
-                       limit = &intel_limits
-                                       [INTEL_LIMIT_G4X_DUAL_CHANNEL_LVDS];
+                       limit = &intel_limits_g4x_dual_channel_lvds;
                else
                        /* LVDS with dual channel */
-                       limit = &intel_limits
-                                       [INTEL_LIMIT_G4X_SINGLE_CHANNEL_LVDS];
+                       limit = &intel_limits_g4x_single_channel_lvds;
        } else if (intel_pipe_has_type(crtc, INTEL_OUTPUT_HDMI) ||
                   intel_pipe_has_type(crtc, INTEL_OUTPUT_ANALOG)) {
-               limit = &intel_limits[INTEL_LIMIT_G4X_HDMI_DAC];
+               limit = &intel_limits_g4x_hdmi;
        } else if (intel_pipe_has_type(crtc, INTEL_OUTPUT_SDVO)) {
-               limit = &intel_limits[INTEL_LIMIT_G4X_SDVO];
+               limit = &intel_limits_g4x_sdvo;
+       } else if (intel_pipe_has_type (crtc, INTEL_OUTPUT_DISPLAYPORT)) {
+               limit = &intel_limits_g4x_display_port;
        } else /* The option is for other outputs */
-               limit = &intel_limits[INTEL_LIMIT_I9XX_SDVO_DAC];
+               limit = &intel_limits_i9xx_sdvo;
 
        return limit;
 }
@@ -495,19 +538,19 @@ static const intel_limit_t *intel_limit(struct drm_crtc *crtc)
                limit = intel_g4x_limit(crtc);
        } else if (IS_I9XX(dev) && !IS_IGD(dev)) {
                if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS))
-                       limit = &intel_limits[INTEL_LIMIT_I9XX_LVDS];
+                       limit = &intel_limits_i9xx_lvds;
                else
-                       limit = &intel_limits[INTEL_LIMIT_I9XX_SDVO_DAC];
+                       limit = &intel_limits_i9xx_sdvo;
        } else if (IS_IGD(dev)) {
                if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS))
-                       limit = &intel_limits[INTEL_LIMIT_IGD_LVDS];
+                       limit = &intel_limits_igd_lvds;
                else
-                       limit = &intel_limits[INTEL_LIMIT_IGD_SDVO_DAC];
+                       limit = &intel_limits_igd_sdvo;
        } else {
                if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS))
-                       limit = &intel_limits[INTEL_LIMIT_I8XX_LVDS];
+                       limit = &intel_limits_i8xx_lvds;
                else
-                       limit = &intel_limits[INTEL_LIMIT_I8XX_DVO_DAC];
+                       limit = &intel_limits_i8xx_dvo;
        }
        return limit;
 }
@@ -764,6 +807,35 @@ out:
        return found;
 }
 
+/* DisplayPort has only two frequencies, 162MHz and 270MHz */
+static bool
+intel_find_pll_g4x_dp(const intel_limit_t *limit, struct drm_crtc *crtc,
+                     int target, int refclk, intel_clock_t *best_clock)
+{
+    intel_clock_t clock;
+    if (target < 200000) {
+       clock.dot = 161670;
+       clock.p = 20;
+       clock.p1 = 2;
+       clock.p2 = 10;
+       clock.n = 0x01;
+       clock.m = 97;
+       clock.m1 = 0x10;
+       clock.m2 = 0x05;
+    } else {
+       clock.dot = 270000;
+       clock.p = 10;
+       clock.p1 = 1;
+       clock.p2 = 10;
+       clock.n = 0x02;
+       clock.m = 108;
+       clock.m1 = 0x12;
+       clock.m2 = 0x06;
+    }
+    memcpy(best_clock, &clock, sizeof(intel_clock_t));
+    return true;
+}
+
 void
 intel_wait_for_vblank(struct drm_device *dev)
 {
@@ -1541,7 +1613,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
        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;
+       bool is_crt = false, is_lvds = false, is_tv = false, is_dp = false;
        struct drm_mode_config *mode_config = &dev->mode_config;
        struct drm_connector *connector;
        const intel_limit_t *limit;
@@ -1585,6 +1657,9 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                case INTEL_OUTPUT_ANALOG:
                        is_crt = true;
                        break;
+               case INTEL_OUTPUT_DISPLAYPORT:
+                       is_dp = true;
+                       break;
                }
 
                num_outputs++;
@@ -1600,6 +1675,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
        } else {
                refclk = 48000;
        }
+       
 
        /*
         * Returns a set of divisors for the desired target clock with the given
@@ -1662,6 +1738,8 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                        else if (IS_IGDNG(dev))
                                dpll |= (sdvo_pixel_multiply - 1) << PLL_REF_SDVO_HDMI_MULTIPLIER_SHIFT;
                }
+               if (is_dp)
+                       dpll |= DPLL_DVO_HIGH_SPEED;
 
                /* compute bitmask from p1 value */
                if (IS_IGD(dev))
@@ -1809,6 +1887,8 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                I915_WRITE(lvds_reg, lvds);
                I915_READ(lvds_reg);
        }
+       if (is_dp)
+               intel_dp_set_m_n(crtc, mode, adjusted_mode);
 
        I915_WRITE(fp_reg, fp);
        I915_WRITE(dpll_reg, dpll);
@@ -2475,6 +2555,8 @@ static void intel_setup_outputs(struct drm_device *dev)
                        found = intel_sdvo_init(dev, SDVOB);
                        if (!found && SUPPORTS_INTEGRATED_HDMI(dev))
                                intel_hdmi_init(dev, SDVOB);
+                       if (!found && SUPPORTS_INTEGRATED_DP(dev))
+                               intel_dp_init(dev, DP_B);
                }
 
                /* Before G4X SDVOC doesn't have its own detect register */
@@ -2487,7 +2569,11 @@ static void intel_setup_outputs(struct drm_device *dev)
                        found = intel_sdvo_init(dev, SDVOC);
                        if (!found && SUPPORTS_INTEGRATED_HDMI(dev))
                                intel_hdmi_init(dev, SDVOC);
+                       if (!found && SUPPORTS_INTEGRATED_DP(dev))
+                               intel_dp_init(dev, DP_C);
                }
+               if (SUPPORTS_INTEGRATED_DP(dev) && (I915_READ(DP_D) & DP_DETECTED))
+                       intel_dp_init(dev, DP_D);
        } else
                intel_dvo_init(dev);
 
@@ -2530,6 +2616,11 @@ static void intel_setup_outputs(struct drm_device *dev)
                                     (1 << 1));
                        clone_mask = (1 << INTEL_OUTPUT_TVOUT);
                        break;
+               case INTEL_OUTPUT_DISPLAYPORT:
+                       crtc_mask = ((1 << 0) |
+                                    (1 << 1));
+                       clone_mask = (1 << INTEL_OUTPUT_DISPLAYPORT);
+                       break;
                }
                encoder->possible_crtcs = crtc_mask;
                encoder->possible_clones = intel_connector_clones(dev, clone_mask);
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
new file mode 100644 (file)
index 0000000..8f8d37d
--- /dev/null
@@ -0,0 +1,1153 @@
+/*
+ * Copyright Â© 2008 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * 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.
+ *
+ * Authors:
+ *    Keith Packard <keithp@keithp.com>
+ *
+ */
+
+#include <linux/i2c.h>
+#include "drmP.h"
+#include "drm.h"
+#include "drm_crtc.h"
+#include "drm_crtc_helper.h"
+#include "intel_drv.h"
+#include "i915_drm.h"
+#include "i915_drv.h"
+#include "intel_dp.h"
+
+#define DP_LINK_STATUS_SIZE    6
+#define DP_LINK_CHECK_TIMEOUT  (10 * 1000)
+
+#define DP_LINK_CONFIGURATION_SIZE     9
+
+struct intel_dp_priv {
+       uint32_t output_reg;
+       uint32_t DP;
+       uint8_t  link_configuration[DP_LINK_CONFIGURATION_SIZE];
+       uint32_t save_DP;
+       uint8_t  save_link_configuration[DP_LINK_CONFIGURATION_SIZE];
+       bool has_audio;
+       int dpms_mode;
+       uint8_t link_bw;
+       uint8_t lane_count;
+       uint8_t dpcd[4];
+       struct intel_output *intel_output;
+       struct i2c_adapter adapter;
+       struct i2c_algo_dp_aux_data algo;
+};
+
+static void
+intel_dp_link_train(struct intel_output *intel_output, uint32_t DP,
+                   uint8_t link_configuration[DP_LINK_CONFIGURATION_SIZE]);
+
+static void
+intel_dp_link_down(struct intel_output *intel_output, uint32_t DP);
+
+static int
+intel_dp_max_lane_count(struct intel_output *intel_output)
+{
+       struct intel_dp_priv   *dp_priv = intel_output->dev_priv;
+       int max_lane_count = 4;
+
+       if (dp_priv->dpcd[0] >= 0x11) {
+               max_lane_count = dp_priv->dpcd[2] & 0x1f;
+               switch (max_lane_count) {
+               case 1: case 2: case 4:
+                       break;
+               default:
+                       max_lane_count = 4;
+               }
+       }
+       return max_lane_count;
+}
+
+static int
+intel_dp_max_link_bw(struct intel_output *intel_output)
+{
+       struct intel_dp_priv   *dp_priv = intel_output->dev_priv;
+       int max_link_bw = dp_priv->dpcd[1];
+
+       switch (max_link_bw) {
+       case DP_LINK_BW_1_62:
+       case DP_LINK_BW_2_7:
+               break;
+       default:
+               max_link_bw = DP_LINK_BW_1_62;
+               break;
+       }
+       return max_link_bw;
+}
+
+static int
+intel_dp_link_clock(uint8_t link_bw)
+{
+       if (link_bw == DP_LINK_BW_2_7)
+               return 270000;
+       else
+               return 162000;
+}
+
+/* I think this is a fiction */
+static int
+intel_dp_link_required(int pixel_clock)
+{
+       return pixel_clock * 3;
+}
+
+static int
+intel_dp_mode_valid(struct drm_connector *connector,
+                   struct drm_display_mode *mode)
+{
+       struct intel_output *intel_output = to_intel_output(connector);
+       int max_link_clock = intel_dp_link_clock(intel_dp_max_link_bw(intel_output));
+       int max_lanes = intel_dp_max_lane_count(intel_output);
+
+       if (intel_dp_link_required(mode->clock) > max_link_clock * max_lanes)
+               return MODE_CLOCK_HIGH;
+
+       if (mode->clock < 10000)
+               return MODE_CLOCK_LOW;
+
+       return MODE_OK;
+}
+
+static uint32_t
+pack_aux(uint8_t *src, int src_bytes)
+{
+       int     i;
+       uint32_t v = 0;
+
+       if (src_bytes > 4)
+               src_bytes = 4;
+       for (i = 0; i < src_bytes; i++)
+               v |= ((uint32_t) src[i]) << ((3-i) * 8);
+       return v;
+}
+
+static void
+unpack_aux(uint32_t src, uint8_t *dst, int dst_bytes)
+{
+       int i;
+       if (dst_bytes > 4)
+               dst_bytes = 4;
+       for (i = 0; i < dst_bytes; i++)
+               dst[i] = src >> ((3-i) * 8);
+}
+
+/* hrawclock is 1/4 the FSB frequency */
+static int
+intel_hrawclk(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       uint32_t clkcfg;
+
+       clkcfg = I915_READ(CLKCFG);
+       switch (clkcfg & CLKCFG_FSB_MASK) {
+       case CLKCFG_FSB_400:
+               return 100;
+       case CLKCFG_FSB_533:
+               return 133;
+       case CLKCFG_FSB_667:
+               return 166;
+       case CLKCFG_FSB_800:
+               return 200;
+       case CLKCFG_FSB_1067:
+               return 266;
+       case CLKCFG_FSB_1333:
+               return 333;
+       /* these two are just a guess; one of them might be right */
+       case CLKCFG_FSB_1600:
+       case CLKCFG_FSB_1600_ALT:
+               return 400;
+       default:
+               return 133;
+       }
+}
+
+static int
+intel_dp_aux_ch(struct intel_output *intel_output,
+               uint8_t *send, int send_bytes,
+               uint8_t *recv, int recv_size)
+{
+       struct intel_dp_priv *dp_priv = intel_output->dev_priv;
+       uint32_t output_reg = dp_priv->output_reg;
+       struct drm_device *dev = intel_output->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       uint32_t ch_ctl = output_reg + 0x10;
+       uint32_t ch_data = ch_ctl + 4;
+       int i;
+       int recv_bytes;
+       uint32_t ctl;
+       uint32_t status;
+       uint32_t aux_clock_divider;
+       int try;
+
+       /* The clock divider is based off the hrawclk,
+        * and would like to run at 2MHz. So, take the
+        * hrawclk value and divide by 2 and use that
+        */
+       aux_clock_divider = intel_hrawclk(dev) / 2;
+       /* Must try at least 3 times according to DP spec */
+       for (try = 0; try < 5; try++) {
+               /* Load the send data into the aux channel data registers */
+               for (i = 0; i < send_bytes; i += 4) {
+                       uint32_t    d = pack_aux(send + i, send_bytes - i);;
+       
+                       I915_WRITE(ch_data + i, d);
+               }
+       
+               ctl = (DP_AUX_CH_CTL_SEND_BUSY |
+                      DP_AUX_CH_CTL_TIME_OUT_400us |
+                      (send_bytes << DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT) |
+                      (5 << DP_AUX_CH_CTL_PRECHARGE_2US_SHIFT) |
+                      (aux_clock_divider << DP_AUX_CH_CTL_BIT_CLOCK_2X_SHIFT) |
+                      DP_AUX_CH_CTL_DONE |
+                      DP_AUX_CH_CTL_TIME_OUT_ERROR |
+                      DP_AUX_CH_CTL_RECEIVE_ERROR);
+       
+               /* Send the command and wait for it to complete */
+               I915_WRITE(ch_ctl, ctl);
+               (void) I915_READ(ch_ctl);
+               for (;;) {
+                       udelay(100);
+                       status = I915_READ(ch_ctl);
+                       if ((status & DP_AUX_CH_CTL_SEND_BUSY) == 0)
+                               break;
+               }
+       
+               /* Clear done status and any errors */
+               I915_WRITE(ch_ctl, (ctl |
+                               DP_AUX_CH_CTL_DONE |
+                               DP_AUX_CH_CTL_TIME_OUT_ERROR |
+                               DP_AUX_CH_CTL_RECEIVE_ERROR));
+               (void) I915_READ(ch_ctl);
+               if ((status & DP_AUX_CH_CTL_TIME_OUT_ERROR) == 0)
+                       break;
+       }
+
+       if ((status & DP_AUX_CH_CTL_DONE) == 0) {
+               printk(KERN_ERR "dp_aux_ch not done status 0x%08x\n", status);
+               return -EBUSY;
+       }
+
+       /* Check for timeout or receive error.
+        * Timeouts occur when the sink is not connected
+        */
+       if (status & DP_AUX_CH_CTL_RECEIVE_ERROR) {
+               printk(KERN_ERR "dp_aux_ch receive error status 0x%08x\n", status);
+               return -EIO;
+       }
+       if (status & DP_AUX_CH_CTL_TIME_OUT_ERROR) {
+               printk(KERN_ERR "dp_aux_ch timeout status 0x%08x\n", status);
+               return -ETIMEDOUT;
+       }
+
+       /* Unload any bytes sent back from the other side */
+       recv_bytes = ((status & DP_AUX_CH_CTL_MESSAGE_SIZE_MASK) >>
+                     DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT);
+
+       if (recv_bytes > recv_size)
+               recv_bytes = recv_size;
+       
+       for (i = 0; i < recv_bytes; i += 4) {
+               uint32_t    d = I915_READ(ch_data + i);
+
+               unpack_aux(d, recv + i, recv_bytes - i);
+       }
+
+       return recv_bytes;
+}
+
+/* Write data to the aux channel in native mode */
+static int
+intel_dp_aux_native_write(struct intel_output *intel_output,
+                         uint16_t address, uint8_t *send, int send_bytes)
+{
+       int ret;
+       uint8_t msg[20];
+       int msg_bytes;
+       uint8_t ack;
+
+       if (send_bytes > 16)
+               return -1;
+       msg[0] = AUX_NATIVE_WRITE << 4;
+       msg[1] = address >> 8;
+       msg[2] = address;
+       msg[3] = send_bytes - 1;
+       memcpy(&msg[4], send, send_bytes);
+       msg_bytes = send_bytes + 4;
+       for (;;) {
+               ret = intel_dp_aux_ch(intel_output, msg, msg_bytes, &ack, 1);
+               if (ret < 0)
+                       return ret;
+               if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_ACK)
+                       break;
+               else if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_DEFER)
+                       udelay(100);
+               else
+                       return -EIO;
+       }
+       return send_bytes;
+}
+
+/* Write a single byte to the aux channel in native mode */
+static int
+intel_dp_aux_native_write_1(struct intel_output *intel_output,
+                           uint16_t address, uint8_t byte)
+{
+       return intel_dp_aux_native_write(intel_output, address, &byte, 1);
+}
+
+/* read bytes from a native aux channel */
+static int
+intel_dp_aux_native_read(struct intel_output *intel_output,
+                        uint16_t address, uint8_t *recv, int recv_bytes)
+{
+       uint8_t msg[4];
+       int msg_bytes;
+       uint8_t reply[20];
+       int reply_bytes;
+       uint8_t ack;
+       int ret;
+
+       msg[0] = AUX_NATIVE_READ << 4;
+       msg[1] = address >> 8;
+       msg[2] = address & 0xff;
+       msg[3] = recv_bytes - 1;
+
+       msg_bytes = 4;
+       reply_bytes = recv_bytes + 1;
+
+       for (;;) {
+               ret = intel_dp_aux_ch(intel_output, msg, msg_bytes,
+                                     reply, reply_bytes);
+               if (ret == 0)
+                       return -EPROTO;
+               if (ret < 0)
+                       return ret;
+               ack = reply[0];
+               if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_ACK) {
+                       memcpy(recv, reply + 1, ret - 1);
+                       return ret - 1;
+               }
+               else if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_DEFER)
+                       udelay(100);
+               else
+                       return -EIO;
+       }
+}
+
+static int
+intel_dp_i2c_aux_ch(struct i2c_adapter *adapter,
+                   uint8_t *send, int send_bytes,
+                   uint8_t *recv, int recv_bytes)
+{
+       struct intel_dp_priv *dp_priv = container_of(adapter,
+                                                    struct intel_dp_priv,
+                                                    adapter);
+       struct intel_output *intel_output = dp_priv->intel_output;
+
+       return intel_dp_aux_ch(intel_output,
+                              send, send_bytes, recv, recv_bytes);
+}
+
+static int
+intel_dp_i2c_init(struct intel_output *intel_output, const char *name)
+{
+       struct intel_dp_priv   *dp_priv = intel_output->dev_priv;
+
+       DRM_ERROR("i2c_init %s\n", name);
+       dp_priv->algo.running = false;
+       dp_priv->algo.address = 0;
+       dp_priv->algo.aux_ch = intel_dp_i2c_aux_ch;
+
+       memset(&dp_priv->adapter, '\0', sizeof (dp_priv->adapter));
+       dp_priv->adapter.owner = THIS_MODULE;
+       dp_priv->adapter.class = I2C_CLASS_DDC;
+       strncpy (dp_priv->adapter.name, name, sizeof dp_priv->adapter.name - 1);
+       dp_priv->adapter.name[sizeof dp_priv->adapter.name - 1] = '\0';
+       dp_priv->adapter.algo_data = &dp_priv->algo;
+       dp_priv->adapter.dev.parent = &intel_output->base.kdev;
+       
+       return i2c_dp_aux_add_bus(&dp_priv->adapter);
+}
+
+static bool
+intel_dp_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode,
+                   struct drm_display_mode *adjusted_mode)
+{
+       struct intel_output *intel_output = enc_to_intel_output(encoder);
+       struct intel_dp_priv   *dp_priv = intel_output->dev_priv;
+       int lane_count, clock;
+       int max_lane_count = intel_dp_max_lane_count(intel_output);
+       int max_clock = intel_dp_max_link_bw(intel_output) == DP_LINK_BW_2_7 ? 1 : 0;
+       static int bws[2] = { DP_LINK_BW_1_62, DP_LINK_BW_2_7 };
+
+       for (lane_count = 1; lane_count <= max_lane_count; lane_count <<= 1) {
+               for (clock = 0; clock <= max_clock; clock++) {
+                       int link_avail = intel_dp_link_clock(bws[clock]) * lane_count;
+
+                       if (intel_dp_link_required(mode->clock) <= link_avail) {
+                               dp_priv->link_bw = bws[clock];
+                               dp_priv->lane_count = lane_count;
+                               adjusted_mode->clock = intel_dp_link_clock(dp_priv->link_bw);
+                               printk(KERN_ERR "link bw %02x lane count %d clock %d\n",
+                                      dp_priv->link_bw, dp_priv->lane_count,
+                                      adjusted_mode->clock);
+                               return true;
+                       }
+               }
+       }
+       return false;
+}
+
+struct intel_dp_m_n {
+       uint32_t        tu;
+       uint32_t        gmch_m;
+       uint32_t        gmch_n;
+       uint32_t        link_m;
+       uint32_t        link_n;
+};
+
+static void
+intel_reduce_ratio(uint32_t *num, uint32_t *den)
+{
+       while (*num > 0xffffff || *den > 0xffffff) {
+               *num >>= 1;
+               *den >>= 1;
+       }
+}
+
+static void
+intel_dp_compute_m_n(int bytes_per_pixel,
+                    int nlanes,
+                    int pixel_clock,
+                    int link_clock,
+                    struct intel_dp_m_n *m_n)
+{
+       m_n->tu = 64;
+       m_n->gmch_m = pixel_clock * bytes_per_pixel;
+       m_n->gmch_n = link_clock * nlanes;
+       intel_reduce_ratio(&m_n->gmch_m, &m_n->gmch_n);
+       m_n->link_m = pixel_clock;
+       m_n->link_n = link_clock;
+       intel_reduce_ratio(&m_n->link_m, &m_n->link_n);
+}
+
+void
+intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode,
+                struct drm_display_mode *adjusted_mode)
+{
+       struct drm_device *dev = crtc->dev;
+       struct drm_mode_config *mode_config = &dev->mode_config;
+       struct drm_connector *connector;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       int lane_count = 4;
+       struct intel_dp_m_n m_n;
+
+       /*
+        * Find the lane count in the intel_output private
+        */
+       list_for_each_entry(connector, &mode_config->connector_list, head) {
+               struct intel_output *intel_output = to_intel_output(connector);
+               struct intel_dp_priv *dp_priv = intel_output->dev_priv;
+
+               if (!connector->encoder || connector->encoder->crtc != crtc)
+                       continue;
+
+               if (intel_output->type == INTEL_OUTPUT_DISPLAYPORT) {
+                       lane_count = dp_priv->lane_count;
+                       break;
+               }
+       }
+
+       /*
+        * Compute the GMCH and Link ratios. The '3' here is
+        * the number of bytes_per_pixel post-LUT, which we always
+        * set up for 8-bits of R/G/B, or 3 bytes total.
+        */
+       intel_dp_compute_m_n(3, lane_count,
+                            mode->clock, adjusted_mode->clock, &m_n);
+
+       if (intel_crtc->pipe == 0) {
+               I915_WRITE(PIPEA_GMCH_DATA_M,
+                      ((m_n.tu - 1) << PIPE_GMCH_DATA_M_TU_SIZE_SHIFT) |
+                      m_n.gmch_m);
+               I915_WRITE(PIPEA_GMCH_DATA_N,
+                      m_n.gmch_n);
+               I915_WRITE(PIPEA_DP_LINK_M, m_n.link_m);
+               I915_WRITE(PIPEA_DP_LINK_N, m_n.link_n);
+       } else {
+               I915_WRITE(PIPEB_GMCH_DATA_M,
+                      ((m_n.tu - 1) << PIPE_GMCH_DATA_M_TU_SIZE_SHIFT) |
+                      m_n.gmch_m);
+               I915_WRITE(PIPEB_GMCH_DATA_N,
+                      m_n.gmch_n);
+               I915_WRITE(PIPEB_DP_LINK_M, m_n.link_m);
+               I915_WRITE(PIPEB_DP_LINK_N, m_n.link_n);
+       }
+}
+
+static void
+intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
+                 struct drm_display_mode *adjusted_mode)
+{
+       struct intel_output *intel_output = enc_to_intel_output(encoder);
+       struct intel_dp_priv *dp_priv = intel_output->dev_priv;
+       struct drm_crtc *crtc = intel_output->enc.crtc;
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+
+       dp_priv->DP = (DP_LINK_TRAIN_OFF |
+                       DP_VOLTAGE_0_4 |
+                       DP_PRE_EMPHASIS_0 |
+                       DP_SYNC_VS_HIGH |
+                       DP_SYNC_HS_HIGH);
+
+       switch (dp_priv->lane_count) {
+       case 1:
+               dp_priv->DP |= DP_PORT_WIDTH_1;
+               break;
+       case 2:
+               dp_priv->DP |= DP_PORT_WIDTH_2;
+               break;
+       case 4:
+               dp_priv->DP |= DP_PORT_WIDTH_4;
+               break;
+       }
+       if (dp_priv->has_audio)
+               dp_priv->DP |= DP_AUDIO_OUTPUT_ENABLE;
+
+       memset(dp_priv->link_configuration, 0, DP_LINK_CONFIGURATION_SIZE);
+       dp_priv->link_configuration[0] = dp_priv->link_bw;
+       dp_priv->link_configuration[1] = dp_priv->lane_count;
+
+       /*
+        * Check for DPCD version > 1.1,
+        * enable enahanced frame stuff in that case
+        */
+       if (dp_priv->dpcd[0] >= 0x11) {
+               dp_priv->link_configuration[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN;
+               dp_priv->DP |= DP_ENHANCED_FRAMING;
+       }
+
+       if (intel_crtc->pipe == 1)
+               dp_priv->DP |= DP_PIPEB_SELECT;
+}
+
+
+static void
+intel_dp_dpms(struct drm_encoder *encoder, int mode)
+{
+       struct intel_output *intel_output = enc_to_intel_output(encoder);
+       struct intel_dp_priv *dp_priv = intel_output->dev_priv;
+       struct drm_device *dev = intel_output->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       uint32_t dp_reg = I915_READ(dp_priv->output_reg);
+
+       if (mode != DRM_MODE_DPMS_ON) {
+               if (dp_reg & DP_PORT_EN)
+                       intel_dp_link_down(intel_output, dp_priv->DP);
+       } else {
+               if (!(dp_reg & DP_PORT_EN))
+                       intel_dp_link_train(intel_output, dp_priv->DP, dp_priv->link_configuration);
+       }
+       dp_priv->dpms_mode = mode;
+}
+
+/*
+ * Fetch AUX CH registers 0x202 - 0x207 which contain
+ * link status information
+ */
+static bool
+intel_dp_get_link_status(struct intel_output *intel_output,
+                        uint8_t link_status[DP_LINK_STATUS_SIZE])
+{
+       int ret;
+
+       ret = intel_dp_aux_native_read(intel_output,
+                                      DP_LANE0_1_STATUS,
+                                      link_status, DP_LINK_STATUS_SIZE);
+       if (ret != DP_LINK_STATUS_SIZE)
+               return false;
+       return true;
+}
+
+static uint8_t
+intel_dp_link_status(uint8_t link_status[DP_LINK_STATUS_SIZE],
+                    int r)
+{
+       return link_status[r - DP_LANE0_1_STATUS];
+}
+
+static void
+intel_dp_save(struct drm_connector *connector)
+{
+       struct intel_output *intel_output = to_intel_output(connector);
+       struct drm_device *dev = intel_output->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_dp_priv *dp_priv = intel_output->dev_priv;
+
+       dp_priv->save_DP = I915_READ(dp_priv->output_reg);
+       intel_dp_aux_native_read(intel_output, DP_LINK_BW_SET,
+                                dp_priv->save_link_configuration,
+                                sizeof (dp_priv->save_link_configuration));
+}
+
+static uint8_t
+intel_get_adjust_request_voltage(uint8_t link_status[DP_LINK_STATUS_SIZE],
+                                int lane)
+{
+       int         i = DP_ADJUST_REQUEST_LANE0_1 + (lane >> 1);
+       int         s = ((lane & 1) ?
+                        DP_ADJUST_VOLTAGE_SWING_LANE1_SHIFT :
+                        DP_ADJUST_VOLTAGE_SWING_LANE0_SHIFT);
+       uint8_t l = intel_dp_link_status(link_status, i);
+
+       return ((l >> s) & 3) << DP_TRAIN_VOLTAGE_SWING_SHIFT;
+}
+
+static uint8_t
+intel_get_adjust_request_pre_emphasis(uint8_t link_status[DP_LINK_STATUS_SIZE],
+                                     int lane)
+{
+       int         i = DP_ADJUST_REQUEST_LANE0_1 + (lane >> 1);
+       int         s = ((lane & 1) ?
+                        DP_ADJUST_PRE_EMPHASIS_LANE1_SHIFT :
+                        DP_ADJUST_PRE_EMPHASIS_LANE0_SHIFT);
+       uint8_t l = intel_dp_link_status(link_status, i);
+
+       return ((l >> s) & 3) << DP_TRAIN_PRE_EMPHASIS_SHIFT;
+}
+
+
+#if 0
+static char    *voltage_names[] = {
+       "0.4V", "0.6V", "0.8V", "1.2V"
+};
+static char    *pre_emph_names[] = {
+       "0dB", "3.5dB", "6dB", "9.5dB"
+};
+static char    *link_train_names[] = {
+       "pattern 1", "pattern 2", "idle", "off"
+};
+#endif
+
+/*
+ * These are source-specific values; current Intel hardware supports
+ * a maximum voltage of 800mV and a maximum pre-emphasis of 6dB
+ */
+#define I830_DP_VOLTAGE_MAX        DP_TRAIN_VOLTAGE_SWING_800
+
+static uint8_t
+intel_dp_pre_emphasis_max(uint8_t voltage_swing)
+{
+       switch (voltage_swing & DP_TRAIN_VOLTAGE_SWING_MASK) {
+       case DP_TRAIN_VOLTAGE_SWING_400:
+               return DP_TRAIN_PRE_EMPHASIS_6;
+       case DP_TRAIN_VOLTAGE_SWING_600:
+               return DP_TRAIN_PRE_EMPHASIS_6;
+       case DP_TRAIN_VOLTAGE_SWING_800:
+               return DP_TRAIN_PRE_EMPHASIS_3_5;
+       case DP_TRAIN_VOLTAGE_SWING_1200:
+       default:
+               return DP_TRAIN_PRE_EMPHASIS_0;
+       }
+}
+
+static void
+intel_get_adjust_train(struct intel_output *intel_output,
+                      uint8_t link_status[DP_LINK_STATUS_SIZE],
+                      int lane_count,
+                      uint8_t train_set[4])
+{
+       uint8_t v = 0;
+       uint8_t p = 0;
+       int lane;
+
+       for (lane = 0; lane < lane_count; lane++) {
+               uint8_t this_v = intel_get_adjust_request_voltage(link_status, lane);
+               uint8_t this_p = intel_get_adjust_request_pre_emphasis(link_status, lane);
+
+               if (this_v > v)
+                       v = this_v;
+               if (this_p > p)
+                       p = this_p;
+       }
+
+       if (v >= I830_DP_VOLTAGE_MAX)
+               v = I830_DP_VOLTAGE_MAX | DP_TRAIN_MAX_SWING_REACHED;
+
+       if (p >= intel_dp_pre_emphasis_max(v))
+               p = intel_dp_pre_emphasis_max(v) | DP_TRAIN_MAX_PRE_EMPHASIS_REACHED;
+
+       for (lane = 0; lane < 4; lane++)
+               train_set[lane] = v | p;
+}
+
+static uint32_t
+intel_dp_signal_levels(uint8_t train_set, int lane_count)
+{
+       uint32_t        signal_levels = 0;
+
+       switch (train_set & DP_TRAIN_VOLTAGE_SWING_MASK) {
+       case DP_TRAIN_VOLTAGE_SWING_400:
+       default:
+               signal_levels |= DP_VOLTAGE_0_4;
+               break;
+       case DP_TRAIN_VOLTAGE_SWING_600:
+               signal_levels |= DP_VOLTAGE_0_6;
+               break;
+       case DP_TRAIN_VOLTAGE_SWING_800:
+               signal_levels |= DP_VOLTAGE_0_8;
+               break;
+       case DP_TRAIN_VOLTAGE_SWING_1200:
+               signal_levels |= DP_VOLTAGE_1_2;
+               break;
+       }
+       switch (train_set & DP_TRAIN_PRE_EMPHASIS_MASK) {
+       case DP_TRAIN_PRE_EMPHASIS_0:
+       default:
+               signal_levels |= DP_PRE_EMPHASIS_0;
+               break;
+       case DP_TRAIN_PRE_EMPHASIS_3_5:
+               signal_levels |= DP_PRE_EMPHASIS_3_5;
+               break;
+       case DP_TRAIN_PRE_EMPHASIS_6:
+               signal_levels |= DP_PRE_EMPHASIS_6;
+               break;
+       case DP_TRAIN_PRE_EMPHASIS_9_5:
+               signal_levels |= DP_PRE_EMPHASIS_9_5;
+               break;
+       }
+       return signal_levels;
+}
+
+static uint8_t
+intel_get_lane_status(uint8_t link_status[DP_LINK_STATUS_SIZE],
+                     int lane)
+{
+       int i = DP_LANE0_1_STATUS + (lane >> 1);
+       int s = (lane & 1) * 4;
+       uint8_t l = intel_dp_link_status(link_status, i);
+
+       return (l >> s) & 0xf;
+}
+
+/* Check for clock recovery is done on all channels */
+static bool
+intel_clock_recovery_ok(uint8_t link_status[DP_LINK_STATUS_SIZE], int lane_count)
+{
+       int lane;
+       uint8_t lane_status;
+
+       for (lane = 0; lane < lane_count; lane++) {
+               lane_status = intel_get_lane_status(link_status, lane);
+               if ((lane_status & DP_LANE_CR_DONE) == 0)
+                       return false;
+       }
+       return true;
+}
+
+/* Check to see if channel eq is done on all channels */
+#define CHANNEL_EQ_BITS (DP_LANE_CR_DONE|\
+                        DP_LANE_CHANNEL_EQ_DONE|\
+                        DP_LANE_SYMBOL_LOCKED)
+static bool
+intel_channel_eq_ok(uint8_t link_status[DP_LINK_STATUS_SIZE], int lane_count)
+{
+       uint8_t lane_align;
+       uint8_t lane_status;
+       int lane;
+
+       lane_align = intel_dp_link_status(link_status,
+                                         DP_LANE_ALIGN_STATUS_UPDATED);
+       if ((lane_align & DP_INTERLANE_ALIGN_DONE) == 0)
+               return false;
+       for (lane = 0; lane < lane_count; lane++) {
+               lane_status = intel_get_lane_status(link_status, lane);
+               if ((lane_status & CHANNEL_EQ_BITS) != CHANNEL_EQ_BITS)
+                       return false;
+       }
+       return true;
+}
+
+static bool
+intel_dp_set_link_train(struct intel_output *intel_output,
+                       uint32_t dp_reg_value,
+                       uint8_t dp_train_pat,
+                       uint8_t train_set[4],
+                       bool first)
+{
+       struct drm_device *dev = intel_output->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_dp_priv *dp_priv = intel_output->dev_priv;
+       int ret;
+
+       I915_WRITE(dp_priv->output_reg, dp_reg_value);
+       POSTING_READ(dp_priv->output_reg);
+       if (first)
+               intel_wait_for_vblank(dev);
+
+       intel_dp_aux_native_write_1(intel_output,
+                                   DP_TRAINING_PATTERN_SET,
+                                   dp_train_pat);
+
+       ret = intel_dp_aux_native_write(intel_output,
+                                       DP_TRAINING_LANE0_SET, train_set, 4);
+       if (ret != 4)
+               return false;
+
+       return true;
+}
+
+static void
+intel_dp_link_train(struct intel_output *intel_output, uint32_t DP,
+                   uint8_t link_configuration[DP_LINK_CONFIGURATION_SIZE])
+{
+       struct drm_device *dev = intel_output->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_dp_priv *dp_priv = intel_output->dev_priv;
+       uint8_t train_set[4];
+       uint8_t link_status[DP_LINK_STATUS_SIZE];
+       int i;
+       uint8_t voltage;
+       bool clock_recovery = false;
+       bool channel_eq = false;
+       bool first = true;
+       int tries;
+
+       /* Write the link configuration data */
+       intel_dp_aux_native_write(intel_output, 0x100,
+                                 link_configuration, DP_LINK_CONFIGURATION_SIZE);
+
+       DP |= DP_PORT_EN;
+       DP &= ~DP_LINK_TRAIN_MASK;
+       memset(train_set, 0, 4);
+       voltage = 0xff;
+       tries = 0;
+       clock_recovery = false;
+       for (;;) {
+               /* Use train_set[0] to set the voltage and pre emphasis values */
+               uint32_t    signal_levels = intel_dp_signal_levels(train_set[0], dp_priv->lane_count);
+               DP = (DP & ~(DP_VOLTAGE_MASK|DP_PRE_EMPHASIS_MASK)) | signal_levels;
+
+               if (!intel_dp_set_link_train(intel_output, DP | DP_LINK_TRAIN_PAT_1,
+                                            DP_TRAINING_PATTERN_1, train_set, first))
+                       break;
+               first = false;
+               /* Set training pattern 1 */
+
+               udelay(100);
+               if (!intel_dp_get_link_status(intel_output, link_status))
+                       break;
+
+               if (intel_clock_recovery_ok(link_status, dp_priv->lane_count)) {
+                       clock_recovery = true;
+                       break;
+               }
+
+               /* Check to see if we've tried the max voltage */
+               for (i = 0; i < dp_priv->lane_count; i++)
+                       if ((train_set[i] & DP_TRAIN_MAX_SWING_REACHED) == 0)
+                               break;
+               if (i == dp_priv->lane_count)
+                       break;
+
+               /* Check to see if we've tried the same voltage 5 times */
+               if ((train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK) == voltage) {
+                       ++tries;
+                       if (tries == 5)
+                               break;
+               } else
+                       tries = 0;
+               voltage = train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK;
+
+               /* Compute new train_set as requested by target */
+               intel_get_adjust_train(intel_output, link_status, dp_priv->lane_count, train_set);
+       }
+
+       /* channel equalization */
+       tries = 0;
+       channel_eq = false;
+       for (;;) {
+               /* Use train_set[0] to set the voltage and pre emphasis values */
+               uint32_t    signal_levels = intel_dp_signal_levels(train_set[0], dp_priv->lane_count);
+               DP = (DP & ~(DP_VOLTAGE_MASK|DP_PRE_EMPHASIS_MASK)) | signal_levels;
+
+               /* channel eq pattern */
+               if (!intel_dp_set_link_train(intel_output, DP | DP_LINK_TRAIN_PAT_2,
+                                            DP_TRAINING_PATTERN_2, train_set,
+                                            false))
+                       break;
+
+               udelay(400);
+               if (!intel_dp_get_link_status(intel_output, link_status))
+                       break;
+
+               if (intel_channel_eq_ok(link_status, dp_priv->lane_count)) {
+                       channel_eq = true;
+                       break;
+               }
+
+               /* Try 5 times */
+               if (tries > 5)
+                       break;
+
+               /* Compute new train_set as requested by target */
+               intel_get_adjust_train(intel_output, link_status, dp_priv->lane_count, train_set);
+               ++tries;
+       }
+
+       I915_WRITE(dp_priv->output_reg, DP | DP_LINK_TRAIN_OFF);
+       POSTING_READ(dp_priv->output_reg);
+       intel_dp_aux_native_write_1(intel_output,
+                                   DP_TRAINING_PATTERN_SET, DP_TRAINING_PATTERN_DISABLE);
+}
+
+static void
+intel_dp_link_down(struct intel_output *intel_output, uint32_t DP)
+{
+       struct drm_device *dev = intel_output->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_dp_priv *dp_priv = intel_output->dev_priv;
+
+       I915_WRITE(dp_priv->output_reg, DP & ~DP_PORT_EN);
+       POSTING_READ(dp_priv->output_reg);
+}
+
+static void
+intel_dp_restore(struct drm_connector *connector)
+{
+       struct intel_output *intel_output = to_intel_output(connector);
+       struct intel_dp_priv *dp_priv = intel_output->dev_priv;
+
+       if (dp_priv->save_DP & DP_PORT_EN)
+               intel_dp_link_train(intel_output, dp_priv->save_DP, dp_priv->save_link_configuration);
+       else
+               intel_dp_link_down(intel_output,  dp_priv->save_DP);
+}
+
+/*
+ * According to DP spec
+ * 5.1.2:
+ *  1. Read DPCD
+ *  2. Configure link according to Receiver Capabilities
+ *  3. Use Link Training from 2.5.3.3 and 3.5.1.3
+ *  4. Check link status on receipt of hot-plug interrupt
+ */
+
+static void
+intel_dp_check_link_status(struct intel_output *intel_output)
+{
+       struct intel_dp_priv *dp_priv = intel_output->dev_priv;
+       uint8_t link_status[DP_LINK_STATUS_SIZE];
+
+       if (!intel_output->enc.crtc)
+               return;
+
+       if (!intel_dp_get_link_status(intel_output, link_status)) {
+               intel_dp_link_down(intel_output, dp_priv->DP);
+               return;
+       }
+
+       if (!intel_channel_eq_ok(link_status, dp_priv->lane_count))
+               intel_dp_link_train(intel_output, dp_priv->DP, dp_priv->link_configuration);
+}
+
+/**
+ * Uses CRT_HOTPLUG_EN and CRT_HOTPLUG_STAT to detect DP connection.
+ *
+ * \return true if DP port is connected.
+ * \return false if DP port is disconnected.
+ */
+static enum drm_connector_status
+intel_dp_detect(struct drm_connector *connector)
+{
+       struct intel_output *intel_output = to_intel_output(connector);
+       struct drm_device *dev = intel_output->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_dp_priv *dp_priv = intel_output->dev_priv;
+       uint32_t temp, bit;
+       enum drm_connector_status status;
+
+       dp_priv->has_audio = false;
+
+       temp = I915_READ(PORT_HOTPLUG_EN);
+
+       I915_WRITE(PORT_HOTPLUG_EN,
+              temp |
+              DPB_HOTPLUG_INT_EN |
+              DPC_HOTPLUG_INT_EN |
+              DPD_HOTPLUG_INT_EN);
+
+       POSTING_READ(PORT_HOTPLUG_EN);
+
+       switch (dp_priv->output_reg) {
+       case DP_B:
+               bit = DPB_HOTPLUG_INT_STATUS;
+               break;
+       case DP_C:
+               bit = DPC_HOTPLUG_INT_STATUS;
+               break;
+       case DP_D:
+               bit = DPD_HOTPLUG_INT_STATUS;
+               break;
+       default:
+               return connector_status_unknown;
+       }
+
+       temp = I915_READ(PORT_HOTPLUG_STAT);
+
+       if ((temp & bit) == 0)
+               return connector_status_disconnected;
+
+       status = connector_status_disconnected;
+       if (intel_dp_aux_native_read(intel_output,
+                                    0x000, dp_priv->dpcd,
+                                    sizeof (dp_priv->dpcd)) == sizeof (dp_priv->dpcd))
+       {
+               if (dp_priv->dpcd[0] != 0)
+                       status = connector_status_connected;
+       }
+       return status;
+}
+
+static int intel_dp_get_modes(struct drm_connector *connector)
+{
+       struct intel_output *intel_output = to_intel_output(connector);
+
+       /* We should parse the EDID data and find out if it has an audio sink
+        */
+
+       return intel_ddc_get_modes(intel_output);
+}
+
+static void
+intel_dp_destroy (struct drm_connector *connector)
+{
+       struct intel_output *intel_output = to_intel_output(connector);
+
+       if (intel_output->i2c_bus)
+               intel_i2c_destroy(intel_output->i2c_bus);
+       drm_sysfs_connector_remove(connector);
+       drm_connector_cleanup(connector);
+       kfree(intel_output);
+}
+
+static const struct drm_encoder_helper_funcs intel_dp_helper_funcs = {
+       .dpms = intel_dp_dpms,
+       .mode_fixup = intel_dp_mode_fixup,
+       .prepare = intel_encoder_prepare,
+       .mode_set = intel_dp_mode_set,
+       .commit = intel_encoder_commit,
+};
+
+static const struct drm_connector_funcs intel_dp_connector_funcs = {
+       .dpms = drm_helper_connector_dpms,
+       .save = intel_dp_save,
+       .restore = intel_dp_restore,
+       .detect = intel_dp_detect,
+       .fill_modes = drm_helper_probe_single_connector_modes,
+       .destroy = intel_dp_destroy,
+};
+
+static const struct drm_connector_helper_funcs intel_dp_connector_helper_funcs = {
+       .get_modes = intel_dp_get_modes,
+       .mode_valid = intel_dp_mode_valid,
+       .best_encoder = intel_best_encoder,
+};
+
+static void intel_dp_enc_destroy(struct drm_encoder *encoder)
+{
+       drm_encoder_cleanup(encoder);
+}
+
+static const struct drm_encoder_funcs intel_dp_enc_funcs = {
+       .destroy = intel_dp_enc_destroy,
+};
+
+void
+intel_dp_hot_plug(struct intel_output *intel_output)
+{
+       struct intel_dp_priv *dp_priv = intel_output->dev_priv;
+
+       if (dp_priv->dpms_mode == DRM_MODE_DPMS_ON)
+               intel_dp_check_link_status(intel_output);
+}
+
+void
+intel_dp_init(struct drm_device *dev, int output_reg)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_connector *connector;
+       struct intel_output *intel_output;
+       struct intel_dp_priv *dp_priv;
+
+       intel_output = kcalloc(sizeof(struct intel_output) + 
+                              sizeof(struct intel_dp_priv), 1, GFP_KERNEL);
+       if (!intel_output)
+               return;
+
+       dp_priv = (struct intel_dp_priv *)(intel_output + 1);
+
+       connector = &intel_output->base;
+       drm_connector_init(dev, connector, &intel_dp_connector_funcs,
+                          DRM_MODE_CONNECTOR_DisplayPort);
+       drm_connector_helper_add(connector, &intel_dp_connector_helper_funcs);
+
+       intel_output->type = INTEL_OUTPUT_DISPLAYPORT;
+
+       connector->interlace_allowed = true;
+       connector->doublescan_allowed = 0;
+
+       dp_priv->intel_output = intel_output;
+       dp_priv->output_reg = output_reg;
+       dp_priv->has_audio = false;
+       dp_priv->dpms_mode = DRM_MODE_DPMS_ON;
+       intel_output->dev_priv = dp_priv;
+
+       drm_encoder_init(dev, &intel_output->enc, &intel_dp_enc_funcs,
+                        DRM_MODE_ENCODER_TMDS);
+       drm_encoder_helper_add(&intel_output->enc, &intel_dp_helper_funcs);
+
+       drm_mode_connector_attach_encoder(&intel_output->base,
+                                         &intel_output->enc);
+       drm_sysfs_connector_add(connector);
+
+       /* Set up the DDC bus. */
+       intel_dp_i2c_init(intel_output,
+                         (output_reg == DP_B) ? "DPDDC-B" :
+                         (output_reg == DP_C) ? "DPDDC-C" : "DPDDC-D");
+       intel_output->ddc_bus = &dp_priv->adapter;
+       intel_output->hot_plug = intel_dp_hot_plug;
+
+       /* For G4X desktop chip, PEG_BAND_GAP_DATA 3:0 must first be written
+        * 0xd.  Failure to do so will result in spurious interrupts being
+        * generated on the port when a cable is not attached.
+        */
+       if (IS_G4X(dev) && !IS_GM45(dev)) {
+               u32 temp = I915_READ(PEG_BAND_GAP_DATA);
+               I915_WRITE(PEG_BAND_GAP_DATA, (temp & ~0xf) | 0xd);
+       }
+}
diff --git a/drivers/gpu/drm/i915/intel_dp.h b/drivers/gpu/drm/i915/intel_dp.h
new file mode 100644 (file)
index 0000000..2b38054
--- /dev/null
@@ -0,0 +1,144 @@
+/*
+ * Copyright Â© 2008 Keith Packard
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  The copyright holders make no representations
+ * about the suitability of this software for any purpose.  It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#ifndef _INTEL_DP_H_
+#define _INTEL_DP_H_
+
+/* From the VESA DisplayPort spec */
+
+#define AUX_NATIVE_WRITE       0x8
+#define AUX_NATIVE_READ                0x9
+#define AUX_I2C_WRITE          0x0
+#define AUX_I2C_READ           0x1
+#define AUX_I2C_STATUS         0x2
+#define AUX_I2C_MOT            0x4
+
+#define AUX_NATIVE_REPLY_ACK   (0x0 << 4)
+#define AUX_NATIVE_REPLY_NACK  (0x1 << 4)
+#define AUX_NATIVE_REPLY_DEFER (0x2 << 4)
+#define AUX_NATIVE_REPLY_MASK  (0x3 << 4)
+
+#define AUX_I2C_REPLY_ACK      (0x0 << 6)
+#define AUX_I2C_REPLY_NACK     (0x1 << 6)
+#define AUX_I2C_REPLY_DEFER    (0x2 << 6)
+#define AUX_I2C_REPLY_MASK     (0x3 << 6)
+
+/* AUX CH addresses */
+#define        DP_LINK_BW_SET          0x100
+# define DP_LINK_BW_1_62                   0x06
+# define DP_LINK_BW_2_7                            0x0a
+
+#define DP_LANE_COUNT_SET      0x101
+# define DP_LANE_COUNT_MASK                0x0f
+# define DP_LANE_COUNT_ENHANCED_FRAME_EN    (1 << 7)
+
+#define DP_TRAINING_PATTERN_SET        0x102
+
+# define DP_TRAINING_PATTERN_DISABLE       0
+# define DP_TRAINING_PATTERN_1             1
+# define DP_TRAINING_PATTERN_2             2
+# define DP_TRAINING_PATTERN_MASK          0x3
+
+# define DP_LINK_QUAL_PATTERN_DISABLE      (0 << 2)
+# define DP_LINK_QUAL_PATTERN_D10_2        (1 << 2)
+# define DP_LINK_QUAL_PATTERN_ERROR_RATE    (2 << 2)
+# define DP_LINK_QUAL_PATTERN_PRBS7        (3 << 2)
+# define DP_LINK_QUAL_PATTERN_MASK         (3 << 2)
+
+# define DP_RECOVERED_CLOCK_OUT_EN         (1 << 4)
+# define DP_LINK_SCRAMBLING_DISABLE        (1 << 5)
+
+# define DP_SYMBOL_ERROR_COUNT_BOTH        (0 << 6)
+# define DP_SYMBOL_ERROR_COUNT_DISPARITY    (1 << 6)
+# define DP_SYMBOL_ERROR_COUNT_SYMBOL      (2 << 6)
+# define DP_SYMBOL_ERROR_COUNT_MASK        (3 << 6)
+
+#define DP_TRAINING_LANE0_SET              0x103
+#define DP_TRAINING_LANE1_SET              0x104
+#define DP_TRAINING_LANE2_SET              0x105
+#define DP_TRAINING_LANE3_SET              0x106
+
+# define DP_TRAIN_VOLTAGE_SWING_MASK       0x3
+# define DP_TRAIN_VOLTAGE_SWING_SHIFT      0
+# define DP_TRAIN_MAX_SWING_REACHED        (1 << 2)
+# define DP_TRAIN_VOLTAGE_SWING_400        (0 << 0)
+# define DP_TRAIN_VOLTAGE_SWING_600        (1 << 0)
+# define DP_TRAIN_VOLTAGE_SWING_800        (2 << 0)
+# define DP_TRAIN_VOLTAGE_SWING_1200       (3 << 0)
+
+# define DP_TRAIN_PRE_EMPHASIS_MASK        (3 << 3)
+# define DP_TRAIN_PRE_EMPHASIS_0           (0 << 3)
+# define DP_TRAIN_PRE_EMPHASIS_3_5         (1 << 3)
+# define DP_TRAIN_PRE_EMPHASIS_6           (2 << 3)
+# define DP_TRAIN_PRE_EMPHASIS_9_5         (3 << 3)
+
+# define DP_TRAIN_PRE_EMPHASIS_SHIFT       3
+# define DP_TRAIN_MAX_PRE_EMPHASIS_REACHED  (1 << 5)
+
+#define DP_DOWNSPREAD_CTRL                 0x107
+# define DP_SPREAD_AMP_0_5                 (1 << 4)
+
+#define DP_MAIN_LINK_CHANNEL_CODING_SET            0x108
+# define DP_SET_ANSI_8B10B                 (1 << 0)
+
+#define DP_LANE0_1_STATUS                  0x202
+#define DP_LANE2_3_STATUS                  0x203
+
+# define DP_LANE_CR_DONE                   (1 << 0)
+# define DP_LANE_CHANNEL_EQ_DONE           (1 << 1)
+# define DP_LANE_SYMBOL_LOCKED             (1 << 2)
+
+#define DP_LANE_ALIGN_STATUS_UPDATED       0x204
+
+#define DP_INTERLANE_ALIGN_DONE                    (1 << 0)
+#define DP_DOWNSTREAM_PORT_STATUS_CHANGED   (1 << 6)
+#define DP_LINK_STATUS_UPDATED             (1 << 7)
+
+#define DP_SINK_STATUS                     0x205
+
+#define DP_RECEIVE_PORT_0_STATUS           (1 << 0)
+#define DP_RECEIVE_PORT_1_STATUS           (1 << 1)
+
+#define DP_ADJUST_REQUEST_LANE0_1          0x206
+#define DP_ADJUST_REQUEST_LANE2_3          0x207
+
+#define DP_ADJUST_VOLTAGE_SWING_LANE0_MASK  0x03
+#define DP_ADJUST_VOLTAGE_SWING_LANE0_SHIFT 0
+#define DP_ADJUST_PRE_EMPHASIS_LANE0_MASK   0x0c
+#define DP_ADJUST_PRE_EMPHASIS_LANE0_SHIFT  2
+#define DP_ADJUST_VOLTAGE_SWING_LANE1_MASK  0x30
+#define DP_ADJUST_VOLTAGE_SWING_LANE1_SHIFT 4
+#define DP_ADJUST_PRE_EMPHASIS_LANE1_MASK   0xc0
+#define DP_ADJUST_PRE_EMPHASIS_LANE1_SHIFT  6
+
+struct i2c_algo_dp_aux_data {
+       bool running;
+       u16 address;
+       int (*aux_ch) (struct i2c_adapter *adapter,
+                      uint8_t *send, int send_bytes,
+                      uint8_t *recv, int recv_bytes);
+};
+
+int
+i2c_dp_aux_add_bus(struct i2c_adapter *adapter);
+
+#endif /* _INTEL_DP_H_ */
diff --git a/drivers/gpu/drm/i915/intel_dp_i2c.c b/drivers/gpu/drm/i915/intel_dp_i2c.c
new file mode 100644 (file)
index 0000000..4e60f14
--- /dev/null
@@ -0,0 +1,272 @@
+/*
+ * Copyright Â© 2009 Keith Packard
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  The copyright holders make no representations
+ * about the suitability of this software for any purpose.  It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/i2c.h>
+#include "intel_dp.h"
+
+/* Run a single AUX_CH I2C transaction, writing/reading data as necessary */
+
+#define MODE_I2C_START 1
+#define MODE_I2C_WRITE 2
+#define MODE_I2C_READ  4
+#define MODE_I2C_STOP  8
+
+static int
+i2c_algo_dp_aux_transaction(struct i2c_adapter *adapter, int mode,
+                           uint8_t write_byte, uint8_t *read_byte)
+{
+       struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data;
+       uint16_t address = algo_data->address;
+       uint8_t msg[5];
+       uint8_t reply[2];
+       int msg_bytes;
+       int reply_bytes;
+       int ret;
+
+       /* Set up the command byte */
+       if (mode & MODE_I2C_READ)
+               msg[0] = AUX_I2C_READ << 4;
+       else
+               msg[0] = AUX_I2C_WRITE << 4;
+
+       if (!(mode & MODE_I2C_STOP))
+               msg[0] |= AUX_I2C_MOT << 4;
+
+       msg[1] = address >> 8;
+       msg[2] = address;
+
+       switch (mode) {
+       case MODE_I2C_WRITE:
+               msg[3] = 0;
+               msg[4] = write_byte;
+               msg_bytes = 5;
+               reply_bytes = 1;
+               break;
+       case MODE_I2C_READ:
+               msg[3] = 0;
+               msg_bytes = 4;
+               reply_bytes = 2;
+               break;
+       default:
+               msg_bytes = 3;
+               reply_bytes = 1;
+               break;
+       }
+
+       for (;;) {
+               ret = (*algo_data->aux_ch)(adapter,
+                                          msg, msg_bytes,
+                                          reply, reply_bytes);
+               if (ret < 0) {
+                       printk(KERN_ERR "aux_ch failed %d\n", ret);
+                       return ret;
+               }
+               switch (reply[0] & AUX_I2C_REPLY_MASK) {
+               case AUX_I2C_REPLY_ACK:
+                       if (mode == MODE_I2C_READ) {
+                               *read_byte = reply[1];
+                       }
+                       return reply_bytes - 1;
+               case AUX_I2C_REPLY_NACK:
+                       printk(KERN_ERR "aux_ch nack\n");
+                       return -EREMOTEIO;
+               case AUX_I2C_REPLY_DEFER:
+                       printk(KERN_ERR "aux_ch defer\n");
+                       udelay(100);
+                       break;
+               default:
+                       printk(KERN_ERR "aux_ch invalid reply 0x%02x\n", reply[0]);
+                       return -EREMOTEIO;
+               }
+       }
+}
+
+/*
+ * I2C over AUX CH
+ */
+
+/*
+ * Send the address. If the I2C link is running, this 'restarts'
+ * the connection with the new address, this is used for doing
+ * a write followed by a read (as needed for DDC)
+ */
+static int
+i2c_algo_dp_aux_address(struct i2c_adapter *adapter, u16 address, bool reading)
+{
+       struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data;
+       int mode = MODE_I2C_START;
+       int ret;
+
+       if (reading)
+               mode |= MODE_I2C_READ;
+       else
+               mode |= MODE_I2C_WRITE;
+       algo_data->address = address;
+       algo_data->running = true;
+       ret = i2c_algo_dp_aux_transaction(adapter, mode, 0, NULL);
+       return ret;
+}
+
+/*
+ * Stop the I2C transaction. This closes out the link, sending
+ * a bare address packet with the MOT bit turned off
+ */
+static void
+i2c_algo_dp_aux_stop(struct i2c_adapter *adapter, bool reading)
+{
+       struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data;
+       int mode = MODE_I2C_STOP;
+
+       if (reading)
+               mode |= MODE_I2C_READ;
+       else
+               mode |= MODE_I2C_WRITE;
+       if (algo_data->running) {
+               (void) i2c_algo_dp_aux_transaction(adapter, mode, 0, NULL);
+               algo_data->running = false;
+       }
+}
+
+/*
+ * Write a single byte to the current I2C address, the
+ * the I2C link must be running or this returns -EIO
+ */
+static int
+i2c_algo_dp_aux_put_byte(struct i2c_adapter *adapter, u8 byte)
+{
+       struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data;
+       int ret;
+
+       if (!algo_data->running)
+               return -EIO;
+
+       ret = i2c_algo_dp_aux_transaction(adapter, MODE_I2C_WRITE, byte, NULL);
+       return ret;
+}
+
+/*
+ * Read a single byte from the current I2C address, the
+ * I2C link must be running or this returns -EIO
+ */
+static int
+i2c_algo_dp_aux_get_byte(struct i2c_adapter *adapter, u8 *byte_ret)
+{
+       struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data;
+       int ret;
+
+       if (!algo_data->running)
+               return -EIO;
+
+       ret = i2c_algo_dp_aux_transaction(adapter, MODE_I2C_READ, 0, byte_ret);
+       return ret;
+}
+
+static int
+i2c_algo_dp_aux_xfer(struct i2c_adapter *adapter,
+                    struct i2c_msg *msgs,
+                    int num)
+{
+       int ret = 0;
+       bool reading = false;
+       int m;
+       int b;
+
+       for (m = 0; m < num; m++) {
+               u16 len = msgs[m].len;
+               u8 *buf = msgs[m].buf;
+               reading = (msgs[m].flags & I2C_M_RD) != 0;
+               ret = i2c_algo_dp_aux_address(adapter, msgs[m].addr, reading);
+               if (ret < 0)
+                       break;
+               if (reading) {
+                       for (b = 0; b < len; b++) {
+                               ret = i2c_algo_dp_aux_get_byte(adapter, &buf[b]);
+                               if (ret < 0)
+                                       break;
+                       }
+               } else {
+                       for (b = 0; b < len; b++) {
+                               ret = i2c_algo_dp_aux_put_byte(adapter, buf[b]);
+                               if (ret < 0)
+                                       break;
+                       }
+               }
+               if (ret < 0)
+                       break;
+       }
+       if (ret >= 0)
+               ret = num;
+       i2c_algo_dp_aux_stop(adapter, reading);
+       printk(KERN_ERR "dp_aux_xfer return %d\n", ret);
+       return ret;
+}
+
+static u32
+i2c_algo_dp_aux_functionality(struct i2c_adapter *adapter)
+{
+       return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL |
+              I2C_FUNC_SMBUS_READ_BLOCK_DATA |
+              I2C_FUNC_SMBUS_BLOCK_PROC_CALL |
+              I2C_FUNC_10BIT_ADDR;
+}
+
+static const struct i2c_algorithm i2c_dp_aux_algo = {
+       .master_xfer    = i2c_algo_dp_aux_xfer,
+       .functionality  = i2c_algo_dp_aux_functionality,
+};
+
+static void
+i2c_dp_aux_reset_bus(struct i2c_adapter *adapter)
+{
+       (void) i2c_algo_dp_aux_address(adapter, 0, false);
+       (void) i2c_algo_dp_aux_stop(adapter, false);
+                                          
+}
+
+static int
+i2c_dp_aux_prepare_bus(struct i2c_adapter *adapter)
+{
+       adapter->algo = &i2c_dp_aux_algo;
+       adapter->retries = 3;
+       i2c_dp_aux_reset_bus(adapter);
+       return 0;
+}
+
+int
+i2c_dp_aux_add_bus(struct i2c_adapter *adapter)
+{
+       int error;
+       
+       error = i2c_dp_aux_prepare_bus(adapter);
+       if (error)
+               return error;
+       error = i2c_add_adapter(adapter);
+       return error;
+}
+EXPORT_SYMBOL(i2c_dp_aux_add_bus);
index cd4b9c5..004541c 100644 (file)
@@ -54,6 +54,7 @@
 #define INTEL_OUTPUT_LVDS 4
 #define INTEL_OUTPUT_TVOUT 5
 #define INTEL_OUTPUT_HDMI 6
+#define INTEL_OUTPUT_DISPLAYPORT 7
 
 #define INTEL_DVO_CHIP_NONE 0
 #define INTEL_DVO_CHIP_LVDS 1
@@ -65,7 +66,6 @@ struct intel_i2c_chan {
        u32 reg; /* GPIO reg */
        struct i2c_adapter adapter;
        struct i2c_algo_bit_data algo;
-        u8 slave_addr;
 };
 
 struct intel_framebuffer {
@@ -79,11 +79,12 @@ struct intel_output {
 
        struct drm_encoder enc;
        int type;
-       struct intel_i2c_chan *i2c_bus; /* for control functions */
-       struct intel_i2c_chan *ddc_bus; /* for DDC only stuff */
+       struct i2c_adapter *i2c_bus;
+       struct i2c_adapter *ddc_bus;
        bool load_detect_temp;
        bool needs_tv_clock;
        void *dev_priv;
+       void (*hot_plug)(struct intel_output *);
 };
 
 struct intel_crtc {
@@ -104,9 +105,9 @@ struct intel_crtc {
 #define enc_to_intel_output(x) container_of(x, struct intel_output, enc)
 #define to_intel_framebuffer(x) container_of(x, struct intel_framebuffer, base)
 
-struct intel_i2c_chan *intel_i2c_create(struct drm_device *dev, const u32 reg,
-                                       const char *name);
-void intel_i2c_destroy(struct intel_i2c_chan *chan);
+struct i2c_adapter *intel_i2c_create(struct drm_device *dev, const u32 reg,
+                                    const char *name);
+void intel_i2c_destroy(struct i2c_adapter *adapter);
 int intel_ddc_get_modes(struct intel_output *intel_output);
 extern bool intel_ddc_probe(struct intel_output *intel_output);
 void intel_i2c_quirk_set(struct drm_device *dev, bool enable);
@@ -116,6 +117,10 @@ extern bool intel_sdvo_init(struct drm_device *dev, int output_device);
 extern void intel_dvo_init(struct drm_device *dev);
 extern void intel_tv_init(struct drm_device *dev);
 extern void intel_lvds_init(struct drm_device *dev);
+extern void intel_dp_init(struct drm_device *dev, int dp_reg);
+void
+intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode,
+                struct drm_display_mode *adjusted_mode);
 
 extern void intel_crtc_load_lut(struct drm_crtc *crtc);
 extern void intel_encoder_prepare (struct drm_encoder *encoder);
index 1ee3007..13bff20 100644 (file)
@@ -384,10 +384,9 @@ void intel_dvo_init(struct drm_device *dev)
 {
        struct intel_output *intel_output;
        struct intel_dvo_device *dvo;
-       struct intel_i2c_chan *i2cbus = NULL;
+       struct i2c_adapter *i2cbus = NULL;
        int ret = 0;
        int i;
-       int gpio_inited = 0;
        int encoder_type = DRM_MODE_ENCODER_NONE;
        intel_output = kzalloc (sizeof(struct intel_output), GFP_KERNEL);
        if (!intel_output)
@@ -420,14 +419,11 @@ void intel_dvo_init(struct drm_device *dev)
                 * It appears that everything is on GPIOE except for panels
                 * on i830 laptops, which are on GPIOB (DVOA).
                 */
-               if (gpio_inited != gpio) {
-                       if (i2cbus != NULL)
-                               intel_i2c_destroy(i2cbus);
-                       if (!(i2cbus = intel_i2c_create(dev, gpio,
-                               gpio == GPIOB ? "DVOI2C_B" : "DVOI2C_E"))) {
-                               continue;
-                       }
-                       gpio_inited = gpio;
+               if (i2cbus != NULL)
+                       intel_i2c_destroy(i2cbus);
+               if (!(i2cbus = intel_i2c_create(dev, gpio,
+                       gpio == GPIOB ? "DVOI2C_B" : "DVOI2C_E"))) {
+                       continue;
                }
 
                if (dvo->dev_ops!= NULL)
index 4ea2a65..9e30daa 100644 (file)
@@ -31,6 +31,7 @@
 #include "drmP.h"
 #include "drm.h"
 #include "drm_crtc.h"
+#include "drm_edid.h"
 #include "intel_drv.h"
 #include "i915_drm.h"
 #include "i915_drv.h"
@@ -56,8 +57,7 @@ static void intel_hdmi_mode_set(struct drm_encoder *encoder,
        sdvox = SDVO_ENCODING_HDMI |
                SDVO_BORDER_ENABLE |
                SDVO_VSYNC_ACTIVE_HIGH |
-               SDVO_HSYNC_ACTIVE_HIGH |
-               SDVO_NULL_PACKETS_DURING_VSYNC;
+               SDVO_HSYNC_ACTIVE_HIGH;
 
        if (hdmi_priv->has_hdmi_sink)
                sdvox |= SDVO_AUDIO_ENABLE;
@@ -129,20 +129,26 @@ static bool intel_hdmi_mode_fixup(struct drm_encoder *encoder,
        return true;
 }
 
-static void
-intel_hdmi_sink_detect(struct drm_connector *connector)
+static enum drm_connector_status
+intel_hdmi_edid_detect(struct drm_connector *connector)
 {
        struct intel_output *intel_output = to_intel_output(connector);
        struct intel_hdmi_priv *hdmi_priv = intel_output->dev_priv;
        struct edid *edid = NULL;
+       enum drm_connector_status status = connector_status_disconnected;
 
        edid = drm_get_edid(&intel_output->base,
-                           &intel_output->ddc_bus->adapter);
-       if (edid != NULL) {
-               hdmi_priv->has_hdmi_sink = drm_detect_hdmi_monitor(edid);
-               kfree(edid);
+                           intel_output->ddc_bus);
+       hdmi_priv->has_hdmi_sink = false;
+       if (edid) {
+               if (edid->input & DRM_EDID_INPUT_DIGITAL) {
+                       status = connector_status_connected;
+                       hdmi_priv->has_hdmi_sink = drm_detect_hdmi_monitor(edid);
+               }
                intel_output->base.display_info.raw_edid = NULL;
+               kfree(edid);
        }
+       return status;
 }
 
 static enum drm_connector_status
@@ -154,11 +160,7 @@ igdng_hdmi_detect(struct drm_connector *connector)
        /* FIXME hotplug detect */
 
        hdmi_priv->has_hdmi_sink = false;
-       intel_hdmi_sink_detect(connector);
-       if (hdmi_priv->has_hdmi_sink)
-               return connector_status_connected;
-       else
-               return connector_status_disconnected;
+       return intel_hdmi_edid_detect(connector);
 }
 
 static enum drm_connector_status
@@ -201,10 +203,9 @@ intel_hdmi_detect(struct drm_connector *connector)
                return connector_status_unknown;
        }
 
-       if ((I915_READ(PORT_HOTPLUG_STAT) & bit) != 0) {
-               intel_hdmi_sink_detect(connector);
-               return connector_status_connected;
-       } else
+       if ((I915_READ(PORT_HOTPLUG_STAT) & bit) != 0)
+               return intel_hdmi_edid_detect(connector);
+       else
                return connector_status_disconnected;
 }
 
index f7061f6..62b8bea 100644 (file)
@@ -124,6 +124,7 @@ static void set_data(void *data, int state_high)
  * @output: driver specific output device
  * @reg: GPIO reg to use
  * @name: name for this bus
+ * @slave_addr: slave address (if fixed)
  *
  * Creates and registers a new i2c bus with the Linux i2c layer, for use
  * in output probing and control (e.g. DDC or SDVO control functions).
@@ -139,8 +140,8 @@ static void set_data(void *data, int state_high)
  *   %GPIOH
  * see PRM for details on how these different busses are used.
  */
-struct intel_i2c_chan *intel_i2c_create(struct drm_device *dev, const u32 reg,
-                                       const char *name)
+struct i2c_adapter *intel_i2c_create(struct drm_device *dev, const u32 reg,
+                                    const char *name)
 {
        struct intel_i2c_chan *chan;
 
@@ -174,7 +175,7 @@ struct intel_i2c_chan *intel_i2c_create(struct drm_device *dev, const u32 reg,
        intel_i2c_quirk_set(dev, false);
        udelay(20);
 
-       return chan;
+       return &chan->adapter;
 
 out_free:
        kfree(chan);
@@ -187,11 +188,16 @@ out_free:
  *
  * Unregister the adapter from the i2c layer, then free the structure.
  */
-void intel_i2c_destroy(struct intel_i2c_chan *chan)
+void intel_i2c_destroy(struct i2c_adapter *adapter)
 {
-       if (!chan)
+       struct intel_i2c_chan *chan;
+
+       if (!adapter)
                return;
 
+       chan = container_of(adapter,
+                           struct intel_i2c_chan,
+                           adapter);
        i2c_del_adapter(&chan->adapter);
        kfree(chan);
 }
index f073ed8..9564ca4 100644 (file)
 
 #define I915_LVDS "i915_lvds"
 
+/*
+ * the following four scaling options are defined.
+ * #define DRM_MODE_SCALE_NON_GPU      0
+ * #define DRM_MODE_SCALE_FULLSCREEN   1
+ * #define DRM_MODE_SCALE_NO_SCALE     2
+ * #define DRM_MODE_SCALE_ASPECT       3
+ */
+
+/* Private structure for the integrated LVDS support */
+struct intel_lvds_priv {
+       int fitting_mode;
+       u32 pfit_control;
+       u32 pfit_pgm_ratios;
+};
+
 /**
  * Sets the backlight level.
  *
@@ -213,10 +228,27 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder,
                                  struct drm_display_mode *mode,
                                  struct drm_display_mode *adjusted_mode)
 {
+       /*
+        * float point operation is not supported . So the PANEL_RATIO_FACTOR
+        * is defined, which can avoid the float point computation when
+        * calculating the panel ratio.
+        */
+#define PANEL_RATIO_FACTOR 8192
        struct drm_device *dev = encoder->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
        struct drm_encoder *tmp_encoder;
+       struct intel_output *intel_output = enc_to_intel_output(encoder);
+       struct intel_lvds_priv *lvds_priv = intel_output->dev_priv;
+       u32 pfit_control = 0, pfit_pgm_ratios = 0;
+       int left_border = 0, right_border = 0, top_border = 0;
+       int bottom_border = 0;
+       bool border = 0;
+       int panel_ratio, desired_ratio, vert_scale, horiz_scale;
+       int horiz_ratio, vert_ratio;
+       u32 hsync_width, vsync_width;
+       u32 hblank_width, vblank_width;
+       u32 hsync_pos, vsync_pos;
 
        /* Should never happen!! */
        if (!IS_I965G(dev) && intel_crtc->pipe == 0) {
@@ -232,7 +264,9 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder,
                        return false;
                }
        }
-
+       /* If we don't have a panel mode, there is nothing we can do */
+       if (dev_priv->panel_fixed_mode == NULL)
+               return true;
        /*
         * If we have timings from the BIOS for the panel, put them in
         * to the adjusted mode.  The CRTC will be set up for this mode,
@@ -256,6 +290,243 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder,
                drm_mode_set_crtcinfo(adjusted_mode, CRTC_INTERLACE_HALVE_V);
        }
 
+       /* Make sure pre-965s set dither correctly */
+       if (!IS_I965G(dev)) {
+               if (dev_priv->panel_wants_dither || dev_priv->lvds_dither)
+                       pfit_control |= PANEL_8TO6_DITHER_ENABLE;
+       }
+
+       /* Native modes don't need fitting */
+       if (adjusted_mode->hdisplay == mode->hdisplay &&
+                       adjusted_mode->vdisplay == mode->vdisplay) {
+               pfit_pgm_ratios = 0;
+               border = 0;
+               goto out;
+       }
+
+       /* 965+ wants fuzzy fitting */
+       if (IS_I965G(dev))
+               pfit_control |= (intel_crtc->pipe << PFIT_PIPE_SHIFT) |
+                                       PFIT_FILTER_FUZZY;
+
+       hsync_width = adjusted_mode->crtc_hsync_end -
+                                       adjusted_mode->crtc_hsync_start;
+       vsync_width = adjusted_mode->crtc_vsync_end -
+                                       adjusted_mode->crtc_vsync_start;
+       hblank_width = adjusted_mode->crtc_hblank_end -
+                                       adjusted_mode->crtc_hblank_start;
+       vblank_width = adjusted_mode->crtc_vblank_end -
+                                       adjusted_mode->crtc_vblank_start;
+       /*
+        * Deal with panel fitting options. Figure out how to stretch the
+        * image based on its aspect ratio & the current panel fitting mode.
+        */
+       panel_ratio = adjusted_mode->hdisplay * PANEL_RATIO_FACTOR /
+                               adjusted_mode->vdisplay;
+       desired_ratio = mode->hdisplay * PANEL_RATIO_FACTOR /
+                               mode->vdisplay;
+       /*
+        * Enable automatic panel scaling for non-native modes so that they fill
+        * the screen.  Should be enabled before the pipe is enabled, according
+        * to register description and PRM.
+        * Change the value here to see the borders for debugging
+        */
+       I915_WRITE(BCLRPAT_A, 0);
+       I915_WRITE(BCLRPAT_B, 0);
+
+       switch (lvds_priv->fitting_mode) {
+       case DRM_MODE_SCALE_NO_SCALE:
+               /*
+                * For centered modes, we have to calculate border widths &
+                * heights and modify the values programmed into the CRTC.
+                */
+               left_border = (adjusted_mode->hdisplay - mode->hdisplay) / 2;
+               right_border = left_border;
+               if (mode->hdisplay & 1)
+                       right_border++;
+               top_border = (adjusted_mode->vdisplay - mode->vdisplay) / 2;
+               bottom_border = top_border;
+               if (mode->vdisplay & 1)
+                       bottom_border++;
+               /* Set active & border values */
+               adjusted_mode->crtc_hdisplay = mode->hdisplay;
+               /* Keep the boder be even */
+               if (right_border & 1)
+                       right_border++;
+               /* use the border directly instead of border minuse one */
+               adjusted_mode->crtc_hblank_start = mode->hdisplay +
+                                               right_border;
+               /* keep the blank width constant */
+               adjusted_mode->crtc_hblank_end =
+                       adjusted_mode->crtc_hblank_start + hblank_width;
+               /* get the hsync pos relative to hblank start */
+               hsync_pos = (hblank_width - hsync_width) / 2;
+               /* keep the hsync pos be even */
+               if (hsync_pos & 1)
+                       hsync_pos++;
+               adjusted_mode->crtc_hsync_start =
+                               adjusted_mode->crtc_hblank_start + hsync_pos;
+               /* keep the hsync width constant */
+               adjusted_mode->crtc_hsync_end =
+                               adjusted_mode->crtc_hsync_start + hsync_width;
+               adjusted_mode->crtc_vdisplay = mode->vdisplay;
+               /* use the border instead of border minus one */
+               adjusted_mode->crtc_vblank_start = mode->vdisplay +
+                                               bottom_border;
+               /* keep the vblank width constant */
+               adjusted_mode->crtc_vblank_end =
+                               adjusted_mode->crtc_vblank_start + vblank_width;
+               /* get the vsync start postion relative to vblank start */
+               vsync_pos = (vblank_width - vsync_width) / 2;
+               adjusted_mode->crtc_vsync_start =
+                               adjusted_mode->crtc_vblank_start + vsync_pos;
+               /* keep the vsync width constant */
+               adjusted_mode->crtc_vsync_end =
+                               adjusted_mode->crtc_vblank_start + vsync_width;
+               border = 1;
+               break;
+       case DRM_MODE_SCALE_ASPECT:
+               /* Scale but preserve the spect ratio */
+               pfit_control |= PFIT_ENABLE;
+               if (IS_I965G(dev)) {
+                       /* 965+ is easy, it does everything in hw */
+                       if (panel_ratio > desired_ratio)
+                               pfit_control |= PFIT_SCALING_PILLAR;
+                       else if (panel_ratio < desired_ratio)
+                               pfit_control |= PFIT_SCALING_LETTER;
+                       else
+                               pfit_control |= PFIT_SCALING_AUTO;
+               } else {
+                       /*
+                        * For earlier chips we have to calculate the scaling
+                        * ratio by hand and program it into the
+                        * PFIT_PGM_RATIO register
+                        */
+                       u32 horiz_bits, vert_bits, bits = 12;
+                       horiz_ratio = mode->hdisplay * PANEL_RATIO_FACTOR/
+                                               adjusted_mode->hdisplay;
+                       vert_ratio = mode->vdisplay * PANEL_RATIO_FACTOR/
+                                               adjusted_mode->vdisplay;
+                       horiz_scale = adjusted_mode->hdisplay *
+                                       PANEL_RATIO_FACTOR / mode->hdisplay;
+                       vert_scale = adjusted_mode->vdisplay *
+                                       PANEL_RATIO_FACTOR / mode->vdisplay;
+
+                       /* retain aspect ratio */
+                       if (panel_ratio > desired_ratio) { /* Pillar */
+                               u32 scaled_width;
+                               scaled_width = mode->hdisplay * vert_scale /
+                                               PANEL_RATIO_FACTOR;
+                               horiz_ratio = vert_ratio;
+                               pfit_control |= (VERT_AUTO_SCALE |
+                                                VERT_INTERP_BILINEAR |
+                                                HORIZ_INTERP_BILINEAR);
+                               /* Pillar will have left/right borders */
+                               left_border = (adjusted_mode->hdisplay -
+                                               scaled_width) / 2;
+                               right_border = left_border;
+                               if (mode->hdisplay & 1) /* odd resolutions */
+                                       right_border++;
+                               /* keep the border be even */
+                               if (right_border & 1)
+                                       right_border++;
+                               adjusted_mode->crtc_hdisplay = scaled_width;
+                               /* use border instead of border minus one */
+                               adjusted_mode->crtc_hblank_start =
+                                       scaled_width + right_border;
+                               /* keep the hblank width constant */
+                               adjusted_mode->crtc_hblank_end =
+                                       adjusted_mode->crtc_hblank_start +
+                                                       hblank_width;
+                               /*
+                                * get the hsync start pos relative to
+                                * hblank start
+                                */
+                               hsync_pos = (hblank_width - hsync_width) / 2;
+                               /* keep the hsync_pos be even */
+                               if (hsync_pos & 1)
+                                       hsync_pos++;
+                               adjusted_mode->crtc_hsync_start =
+                                       adjusted_mode->crtc_hblank_start +
+                                                       hsync_pos;
+                               /* keept hsync width constant */
+                               adjusted_mode->crtc_hsync_end =
+                                       adjusted_mode->crtc_hsync_start +
+                                                       hsync_width;
+                               border = 1;
+                       } else if (panel_ratio < desired_ratio) { /* letter */
+                               u32 scaled_height = mode->vdisplay *
+                                       horiz_scale / PANEL_RATIO_FACTOR;
+                               vert_ratio = horiz_ratio;
+                               pfit_control |= (HORIZ_AUTO_SCALE |
+                                                VERT_INTERP_BILINEAR |
+                                                HORIZ_INTERP_BILINEAR);
+                               /* Letterbox will have top/bottom border */
+                               top_border = (adjusted_mode->vdisplay -
+                                       scaled_height) / 2;
+                               bottom_border = top_border;
+                               if (mode->vdisplay & 1)
+                                       bottom_border++;
+                               adjusted_mode->crtc_vdisplay = scaled_height;
+                               /* use border instead of border minus one */
+                               adjusted_mode->crtc_vblank_start =
+                                       scaled_height + bottom_border;
+                               /* keep the vblank width constant */
+                               adjusted_mode->crtc_vblank_end =
+                                       adjusted_mode->crtc_vblank_start +
+                                                       vblank_width;
+                               /*
+                                * get the vsync start pos relative to
+                                * vblank start
+                                */
+                               vsync_pos = (vblank_width - vsync_width) / 2;
+                               adjusted_mode->crtc_vsync_start =
+                                       adjusted_mode->crtc_vblank_start +
+                                                       vsync_pos;
+                               /* keep the vsync width constant */
+                               adjusted_mode->crtc_vsync_end =
+                                       adjusted_mode->crtc_vsync_start +
+                                                       vsync_width;
+                               border = 1;
+                       } else {
+                       /* Aspects match, Let hw scale both directions */
+                               pfit_control |= (VERT_AUTO_SCALE |
+                                                HORIZ_AUTO_SCALE |
+                                                VERT_INTERP_BILINEAR |
+                                                HORIZ_INTERP_BILINEAR);
+                       }
+                       horiz_bits = (1 << bits) * horiz_ratio /
+                                       PANEL_RATIO_FACTOR;
+                       vert_bits = (1 << bits) * vert_ratio /
+                                       PANEL_RATIO_FACTOR;
+                       pfit_pgm_ratios =
+                               ((vert_bits << PFIT_VERT_SCALE_SHIFT) &
+                                               PFIT_VERT_SCALE_MASK) |
+                               ((horiz_bits << PFIT_HORIZ_SCALE_SHIFT) &
+                                               PFIT_HORIZ_SCALE_MASK);
+               }
+               break;
+
+       case DRM_MODE_SCALE_FULLSCREEN:
+               /*
+                * Full scaling, even if it changes the aspect ratio.
+                * Fortunately this is all done for us in hw.
+                */
+               pfit_control |= PFIT_ENABLE;
+               if (IS_I965G(dev))
+                       pfit_control |= PFIT_SCALING_AUTO;
+               else
+                       pfit_control |= (VERT_AUTO_SCALE | HORIZ_AUTO_SCALE |
+                                        VERT_INTERP_BILINEAR |
+                                        HORIZ_INTERP_BILINEAR);
+               break;
+       default:
+               break;
+       }
+
+out:
+       lvds_priv->pfit_control = pfit_control;
+       lvds_priv->pfit_pgm_ratios = pfit_pgm_ratios;
        /*
         * XXX: It would be nice to support lower refresh rates on the
         * panels to reduce power consumption, and perhaps match the
@@ -301,8 +572,8 @@ static void intel_lvds_mode_set(struct drm_encoder *encoder,
 {
        struct drm_device *dev = encoder->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
-       u32 pfit_control;
+       struct intel_output *intel_output = enc_to_intel_output(encoder);
+       struct intel_lvds_priv *lvds_priv = intel_output->dev_priv;
 
        /*
         * The LVDS pin pair will already have been turned on in the
@@ -319,22 +590,8 @@ static void intel_lvds_mode_set(struct drm_encoder *encoder,
         * screen.  Should be enabled before the pipe is enabled, according to
         * register description and PRM.
         */
-       if (mode->hdisplay != adjusted_mode->hdisplay ||
-           mode->vdisplay != adjusted_mode->vdisplay)
-               pfit_control = (PFIT_ENABLE | VERT_AUTO_SCALE |
-                               HORIZ_AUTO_SCALE | VERT_INTERP_BILINEAR |
-                               HORIZ_INTERP_BILINEAR);
-       else
-               pfit_control = 0;
-
-       if (!IS_I965G(dev)) {
-               if (dev_priv->panel_wants_dither || dev_priv->lvds_dither)
-                       pfit_control |= PANEL_8TO6_DITHER_ENABLE;
-       }
-       else
-               pfit_control |= intel_crtc->pipe << PFIT_PIPE_SHIFT;
-
-       I915_WRITE(PFIT_CONTROL, pfit_control);
+       I915_WRITE(PFIT_PGM_RATIOS, lvds_priv->pfit_pgm_ratios);
+       I915_WRITE(PFIT_CONTROL, lvds_priv->pfit_control);
 }
 
 /**
@@ -406,6 +663,34 @@ static int intel_lvds_set_property(struct drm_connector *connector,
                                   struct drm_property *property,
                                   uint64_t value)
 {
+       struct drm_device *dev = connector->dev;
+       struct intel_output *intel_output =
+                       to_intel_output(connector);
+
+       if (property == dev->mode_config.scaling_mode_property &&
+                               connector->encoder) {
+               struct drm_crtc *crtc = connector->encoder->crtc;
+               struct intel_lvds_priv *lvds_priv = intel_output->dev_priv;
+               if (value == DRM_MODE_SCALE_NON_GPU) {
+                       DRM_DEBUG_KMS(I915_LVDS,
+                                       "non_GPU property is unsupported\n");
+                       return 0;
+               }
+               if (lvds_priv->fitting_mode == value) {
+                       /* the LVDS scaling property is not changed */
+                       return 0;
+               }
+               lvds_priv->fitting_mode = value;
+               if (crtc && crtc->enabled) {
+                       /*
+                        * If the CRTC is enabled, the display will be changed
+                        * according to the new panel fitting mode.
+                        */
+                       drm_crtc_helper_set_mode(crtc, &crtc->mode,
+                               crtc->x, crtc->y, crtc->fb);
+               }
+       }
+
        return 0;
 }
 
@@ -456,7 +741,7 @@ static const struct dmi_system_id intel_no_lvds[] = {
                .callback = intel_no_lvds_dmi_callback,
                .ident = "Apple Mac Mini (Core series)",
                .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
+                       DMI_MATCH(DMI_SYS_VENDOR, "Apple"),
                        DMI_MATCH(DMI_PRODUCT_NAME, "Macmini1,1"),
                },
        },
@@ -464,7 +749,7 @@ static const struct dmi_system_id intel_no_lvds[] = {
                .callback = intel_no_lvds_dmi_callback,
                .ident = "Apple Mac Mini (Core 2 series)",
                .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
+                       DMI_MATCH(DMI_SYS_VENDOR, "Apple"),
                        DMI_MATCH(DMI_PRODUCT_NAME, "Macmini2,1"),
                },
        },
@@ -518,6 +803,7 @@ void intel_lvds_init(struct drm_device *dev)
        struct drm_encoder *encoder;
        struct drm_display_mode *scan; /* *modes, *bios_mode; */
        struct drm_crtc *crtc;
+       struct intel_lvds_priv *lvds_priv;
        u32 lvds;
        int pipe, gpio = GPIOC;
 
@@ -531,7 +817,8 @@ void intel_lvds_init(struct drm_device *dev)
                gpio = PCH_GPIOC;
        }
 
-       intel_output = kzalloc(sizeof(struct intel_output), GFP_KERNEL);
+       intel_output = kzalloc(sizeof(struct intel_output) +
+                               sizeof(struct intel_lvds_priv), GFP_KERNEL);
        if (!intel_output) {
                return;
        }
@@ -553,7 +840,18 @@ void intel_lvds_init(struct drm_device *dev)
        connector->interlace_allowed = false;
        connector->doublescan_allowed = false;
 
+       lvds_priv = (struct intel_lvds_priv *)(intel_output + 1);
+       intel_output->dev_priv = lvds_priv;
+       /* create the scaling mode property */
+       drm_mode_create_scaling_mode_property(dev);
+       /*
+        * the initial panel fitting mode will be FULL_SCREEN.
+        */
 
+       drm_connector_attach_property(&intel_output->base,
+                                     dev->mode_config.scaling_mode_property,
+                                     DRM_MODE_SCALE_FULLSCREEN);
+       lvds_priv->fitting_mode = DRM_MODE_SCALE_FULLSCREEN;
        /*
         * LVDS discovery:
         * 1) check for EDID on DDC
@@ -649,5 +947,5 @@ failed:
        if (intel_output->ddc_bus)
                intel_i2c_destroy(intel_output->ddc_bus);
        drm_connector_cleanup(connector);
-       kfree(connector);
+       kfree(intel_output);
 }
index e0910fe..67e2f46 100644 (file)
@@ -53,10 +53,9 @@ bool intel_ddc_probe(struct intel_output *intel_output)
                }
        };
 
-       intel_i2c_quirk_set(intel_output->ddc_bus->drm_dev, true);
-       ret = i2c_transfer(&intel_output->ddc_bus->adapter, msgs, 2);
-       intel_i2c_quirk_set(intel_output->ddc_bus->drm_dev, false);
-
+       intel_i2c_quirk_set(intel_output->base.dev, true);
+       ret = i2c_transfer(intel_output->ddc_bus, msgs, 2);
+       intel_i2c_quirk_set(intel_output->base.dev, false);
        if (ret == 2)
                return true;
 
@@ -74,10 +73,9 @@ int intel_ddc_get_modes(struct intel_output *intel_output)
        struct edid *edid;
        int ret = 0;
 
-       intel_i2c_quirk_set(intel_output->ddc_bus->drm_dev, true);
-       edid = drm_get_edid(&intel_output->base,
-                           &intel_output->ddc_bus->adapter);
-       intel_i2c_quirk_set(intel_output->ddc_bus->drm_dev, false);
+       intel_i2c_quirk_set(intel_output->base.dev, true);
+       edid = drm_get_edid(&intel_output->base, intel_output->ddc_bus);
+       intel_i2c_quirk_set(intel_output->base.dev, false);
        if (edid) {
                drm_mode_connector_update_edid_property(&intel_output->base,
                                                        edid);
index 9a00adb..f034737 100644 (file)
@@ -38,8 +38,7 @@
 #undef SDVO_DEBUG
 #define I915_SDVO      "i915_sdvo"
 struct intel_sdvo_priv {
-       struct intel_i2c_chan *i2c_bus;
-       int slaveaddr;
+       u8 slave_addr;
 
        /* Register for the SDVO device: SDVOB or SDVOC */
        int output_device;
@@ -146,13 +145,13 @@ static bool intel_sdvo_read_byte(struct intel_output *intel_output, u8 addr,
 
        struct i2c_msg msgs[] = {
                {
-                       .addr = sdvo_priv->i2c_bus->slave_addr,
+                       .addr = sdvo_priv->slave_addr >> 1,
                        .flags = 0,
                        .len = 1,
                        .buf = out_buf,
                },
                {
-                       .addr = sdvo_priv->i2c_bus->slave_addr,
+                       .addr = sdvo_priv->slave_addr >> 1,
                        .flags = I2C_M_RD,
                        .len = 1,
                        .buf = buf,
@@ -162,7 +161,7 @@ static bool intel_sdvo_read_byte(struct intel_output *intel_output, u8 addr,
        out_buf[0] = addr;
        out_buf[1] = 0;
 
-       if ((ret = i2c_transfer(&sdvo_priv->i2c_bus->adapter, msgs, 2)) == 2)
+       if ((ret = i2c_transfer(intel_output->i2c_bus, msgs, 2)) == 2)
        {
                *ch = buf[0];
                return true;
@@ -175,10 +174,11 @@ static bool intel_sdvo_read_byte(struct intel_output *intel_output, u8 addr,
 static bool intel_sdvo_write_byte(struct intel_output *intel_output, int addr,
                                  u8 ch)
 {
+       struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
        u8 out_buf[2];
        struct i2c_msg msgs[] = {
                {
-                       .addr = intel_output->i2c_bus->slave_addr,
+                       .addr = sdvo_priv->slave_addr >> 1,
                        .flags = 0,
                        .len = 2,
                        .buf = out_buf,
@@ -188,7 +188,7 @@ static bool intel_sdvo_write_byte(struct intel_output *intel_output, int addr,
        out_buf[0] = addr;
        out_buf[1] = ch;
 
-       if (i2c_transfer(&intel_output->i2c_bus->adapter, msgs, 1) == 1)
+       if (i2c_transfer(intel_output->i2c_bus, msgs, 1) == 1)
        {
                return true;
        }
@@ -1369,9 +1369,8 @@ intel_sdvo_hdmi_sink_detect(struct drm_connector *connector)
        struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
        struct edid *edid = NULL;
 
-       intel_sdvo_set_control_bus_switch(intel_output, sdvo_priv->ddc_bus);
        edid = drm_get_edid(&intel_output->base,
-                           &intel_output->ddc_bus->adapter);
+                           intel_output->ddc_bus);
        if (edid != NULL) {
                sdvo_priv->is_hdmi = drm_detect_hdmi_monitor(edid);
                kfree(edid);
@@ -1549,7 +1548,6 @@ static void intel_sdvo_get_tv_modes(struct drm_connector *connector)
 static void intel_sdvo_get_lvds_modes(struct drm_connector *connector)
 {
        struct intel_output *intel_output = to_intel_output(connector);
-       struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
        struct drm_i915_private *dev_priv = connector->dev->dev_private;
 
        /*
@@ -1557,8 +1555,6 @@ static void intel_sdvo_get_lvds_modes(struct drm_connector *connector)
         * Assume that the preferred modes are
         * arranged in priority order.
         */
-       /* set the bus switch and get the modes */
-       intel_sdvo_set_control_bus_switch(intel_output, sdvo_priv->ddc_bus);
        intel_ddc_get_modes(intel_output);
        if (list_empty(&connector->probed_modes) == false)
                return;
@@ -1709,7 +1705,7 @@ intel_sdvo_chan_to_intel_output(struct intel_i2c_chan *chan)
 
        list_for_each_entry(connector,
                        &dev->mode_config.connector_list, head) {
-               if (to_intel_output(connector)->ddc_bus == chan) {
+               if (to_intel_output(connector)->ddc_bus == &chan->adapter) {
                        intel_output = to_intel_output(connector);
                        break;
                }
@@ -1723,7 +1719,7 @@ static int intel_sdvo_master_xfer(struct i2c_adapter *i2c_adap,
        struct intel_output *intel_output;
        struct intel_sdvo_priv *sdvo_priv;
        struct i2c_algo_bit_data *algo_data;
-       struct i2c_algorithm *algo;
+       const struct i2c_algorithm *algo;
 
        algo_data = (struct i2c_algo_bit_data *)i2c_adap->algo_data;
        intel_output =
@@ -1733,7 +1729,7 @@ static int intel_sdvo_master_xfer(struct i2c_adapter *i2c_adap,
                return -EINVAL;
 
        sdvo_priv = intel_output->dev_priv;
-       algo = (struct i2c_algorithm *)intel_output->i2c_bus->adapter.algo;
+       algo = intel_output->i2c_bus->algo;
 
        intel_sdvo_set_control_bus_switch(intel_output, sdvo_priv->ddc_bus);
        return algo->master_xfer(i2c_adap, msgs, num);
@@ -1785,13 +1781,11 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device)
        struct drm_connector *connector;
        struct intel_output *intel_output;
        struct intel_sdvo_priv *sdvo_priv;
-       struct intel_i2c_chan *i2cbus = NULL;
-       struct intel_i2c_chan *ddcbus = NULL;
+
        int connector_type;
        u8 ch[0x40];
        int i;
-       int encoder_type, output_id;
-       u8 slave_addr;
+       int encoder_type;
 
        intel_output = kcalloc(sizeof(struct intel_output)+sizeof(struct intel_sdvo_priv), 1, GFP_KERNEL);
        if (!intel_output) {
@@ -1799,29 +1793,24 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device)
        }
 
        sdvo_priv = (struct intel_sdvo_priv *)(intel_output + 1);
+       sdvo_priv->output_device = output_device;
+
+       intel_output->dev_priv = sdvo_priv;
        intel_output->type = INTEL_OUTPUT_SDVO;
 
        /* setup the DDC bus. */
        if (output_device == SDVOB)
-               i2cbus = intel_i2c_create(dev, GPIOE, "SDVOCTRL_E for SDVOB");
+               intel_output->i2c_bus = intel_i2c_create(dev, GPIOE, "SDVOCTRL_E for SDVOB");
        else
-               i2cbus = intel_i2c_create(dev, GPIOE, "SDVOCTRL_E for SDVOC");
+               intel_output->i2c_bus = intel_i2c_create(dev, GPIOE, "SDVOCTRL_E for SDVOC");
 
-       if (!i2cbus)
+       if (!intel_output->i2c_bus)
                goto err_inteloutput;
 
-       slave_addr = intel_sdvo_get_slave_addr(dev, output_device);
-       sdvo_priv->i2c_bus = i2cbus;
+       sdvo_priv->slave_addr = intel_sdvo_get_slave_addr(dev, output_device);
 
-       if (output_device == SDVOB) {
-               output_id = 1;
-       } else {
-               output_id = 2;
-       }
-       sdvo_priv->i2c_bus->slave_addr = slave_addr >> 1;
-       sdvo_priv->output_device = output_device;
-       intel_output->i2c_bus = i2cbus;
-       intel_output->dev_priv = sdvo_priv;
+       /* Save the bit-banging i2c functionality for use by the DDC wrapper */
+       intel_sdvo_i2c_bit_algo.functionality = intel_output->i2c_bus->algo->functionality;
 
        /* Read the regs to test if we can talk to the device */
        for (i = 0; i < 0x40; i++) {
@@ -1835,17 +1824,15 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device)
 
        /* setup the DDC bus. */
        if (output_device == SDVOB)
-               ddcbus = intel_i2c_create(dev, GPIOE, "SDVOB DDC BUS");
+               intel_output->ddc_bus = intel_i2c_create(dev, GPIOE, "SDVOB DDC BUS");
        else
-               ddcbus = intel_i2c_create(dev, GPIOE, "SDVOC DDC BUS");
+               intel_output->ddc_bus = intel_i2c_create(dev, GPIOE, "SDVOC DDC BUS");
 
-       if (ddcbus == NULL)
+       if (intel_output->ddc_bus == NULL)
                goto err_i2c;
 
-       intel_sdvo_i2c_bit_algo.functionality =
-               intel_output->i2c_bus->adapter.algo->functionality;
-       ddcbus->adapter.algo = &intel_sdvo_i2c_bit_algo;
-       intel_output->ddc_bus = ddcbus;
+       /* Wrap with our custom algo which switches to DDC mode */
+       intel_output->ddc_bus->algo = &intel_sdvo_i2c_bit_algo;
 
        /* In defaut case sdvo lvds is false */
        sdvo_priv->is_lvds = false;
@@ -1965,9 +1952,10 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device)
        return true;
 
 err_i2c:
-       if (ddcbus != NULL)
+       if (intel_output->ddc_bus != NULL)
                intel_i2c_destroy(intel_output->ddc_bus);
-       intel_i2c_destroy(intel_output->i2c_bus);
+       if (intel_output->i2c_bus != NULL)
+               intel_i2c_destroy(intel_output->i2c_bus);
 err_inteloutput:
        kfree(intel_output);
 
index ea68992..a43c98e 100644 (file)
@@ -1383,34 +1383,31 @@ intel_tv_detect_type (struct drm_crtc *crtc, struct intel_output *intel_output)
        /*
         * Detect TV by polling)
         */
-       if (intel_output->load_detect_temp) {
-               /* TV not currently running, prod it with destructive detect */
-               save_tv_dac = tv_dac;
-               tv_ctl = I915_READ(TV_CTL);
-               save_tv_ctl = tv_ctl;
-               tv_ctl &= ~TV_ENC_ENABLE;
-               tv_ctl &= ~TV_TEST_MODE_MASK;
-               tv_ctl |= TV_TEST_MODE_MONITOR_DETECT;
-               tv_dac &= ~TVDAC_SENSE_MASK;
-               tv_dac &= ~DAC_A_MASK;
-               tv_dac &= ~DAC_B_MASK;
-               tv_dac &= ~DAC_C_MASK;
-               tv_dac |= (TVDAC_STATE_CHG_EN |
-                          TVDAC_A_SENSE_CTL |
-                          TVDAC_B_SENSE_CTL |
-                          TVDAC_C_SENSE_CTL |
-                          DAC_CTL_OVERRIDE |
-                          DAC_A_0_7_V |
-                          DAC_B_0_7_V |
-                          DAC_C_0_7_V);
-               I915_WRITE(TV_CTL, tv_ctl);
-               I915_WRITE(TV_DAC, tv_dac);
-               intel_wait_for_vblank(dev);
-               tv_dac = I915_READ(TV_DAC);
-               I915_WRITE(TV_DAC, save_tv_dac);
-               I915_WRITE(TV_CTL, save_tv_ctl);
-               intel_wait_for_vblank(dev);
-       }
+       save_tv_dac = tv_dac;
+       tv_ctl = I915_READ(TV_CTL);
+       save_tv_ctl = tv_ctl;
+       tv_ctl &= ~TV_ENC_ENABLE;
+       tv_ctl &= ~TV_TEST_MODE_MASK;
+       tv_ctl |= TV_TEST_MODE_MONITOR_DETECT;
+       tv_dac &= ~TVDAC_SENSE_MASK;
+       tv_dac &= ~DAC_A_MASK;
+       tv_dac &= ~DAC_B_MASK;
+       tv_dac &= ~DAC_C_MASK;
+       tv_dac |= (TVDAC_STATE_CHG_EN |
+                  TVDAC_A_SENSE_CTL |
+                  TVDAC_B_SENSE_CTL |
+                  TVDAC_C_SENSE_CTL |
+                  DAC_CTL_OVERRIDE |
+                  DAC_A_0_7_V |
+                  DAC_B_0_7_V |
+                  DAC_C_0_7_V);
+       I915_WRITE(TV_CTL, tv_ctl);
+       I915_WRITE(TV_DAC, tv_dac);
+       intel_wait_for_vblank(dev);
+       tv_dac = I915_READ(TV_DAC);
+       I915_WRITE(TV_DAC, save_tv_dac);
+       I915_WRITE(TV_CTL, save_tv_ctl);
+       intel_wait_for_vblank(dev);
        /*
         *  A B C
         *  0 1 1 Composite
index f30aa72..f97563d 100644 (file)
 #include "atom.h"
 
 /*
+ * Clear GPU surface registers.
+ */
+static void radeon_surface_init(struct radeon_device *rdev)
+{
+       /* FIXME: check this out */
+       if (rdev->family < CHIP_R600) {
+               int i;
+
+               for (i = 0; i < 8; i++) {
+                       WREG32(RADEON_SURFACE0_INFO +
+                              i * (RADEON_SURFACE1_INFO - RADEON_SURFACE0_INFO),
+                              0);
+               }
+       }
+}
+
+/*
  * GPU scratch registers helpers function.
  */
 static void radeon_scratch_init(struct radeon_device *rdev)
@@ -496,6 +513,8 @@ int radeon_device_init(struct radeon_device *rdev,
        radeon_errata(rdev);
        /* Initialize scratch registers */
        radeon_scratch_init(rdev);
+       /* Initialize surface registers */
+       radeon_surface_init(rdev);
 
        /* TODO: disable VGA need to use VGA request */
        /* BIOS*/
@@ -604,9 +623,6 @@ int radeon_device_init(struct radeon_device *rdev,
        if (r) {
                return r;
        }
-       if (rdev->fbdev_rfb && rdev->fbdev_rfb->obj) {
-               rdev->fbdev_robj = rdev->fbdev_rfb->obj->driver_private;
-       }
        if (!ret) {
                DRM_INFO("radeon: kernel modesetting successfully initialized.\n");
        }
index 09c9fb9..84ba69f 100644 (file)
@@ -345,7 +345,7 @@ static void __exit radeon_exit(void)
        drm_exit(driver);
 }
 
-late_initcall(radeon_init);
+module_init(radeon_init);
 module_exit(radeon_exit);
 
 MODULE_AUTHOR(DRIVER_AUTHOR);
index fa86d39..9e8f191 100644 (file)
@@ -478,14 +478,16 @@ int radeonfb_create(struct radeon_device *rdev,
 {
        struct fb_info *info;
        struct radeon_fb_device *rfbdev;
-       struct drm_framebuffer *fb;
+       struct drm_framebuffer *fb = NULL;
        struct radeon_framebuffer *rfb;
        struct drm_mode_fb_cmd mode_cmd;
        struct drm_gem_object *gobj = NULL;
        struct radeon_object *robj = NULL;
        struct device *device = &rdev->pdev->dev;
        int size, aligned_size, ret;
+       u64 fb_gpuaddr;
        void *fbptr = NULL;
+       unsigned long tmp;
 
        mode_cmd.width = surface_width;
        mode_cmd.height = surface_height;
@@ -498,11 +500,12 @@ int radeonfb_create(struct radeon_device *rdev,
        aligned_size = ALIGN(size, PAGE_SIZE);
 
        ret = radeon_gem_object_create(rdev, aligned_size, 0,
-                                      RADEON_GEM_DOMAIN_VRAM,
-                                      false, ttm_bo_type_kernel,
-                                      false, &gobj);
+                       RADEON_GEM_DOMAIN_VRAM,
+                       false, ttm_bo_type_kernel,
+                       false, &gobj);
        if (ret) {
-               printk(KERN_ERR "failed to allocate framebuffer\n");
+               printk(KERN_ERR "failed to allocate framebuffer (%d %d)\n",
+                      surface_width, surface_height);
                ret = -ENOMEM;
                goto out;
        }
@@ -515,12 +518,19 @@ int radeonfb_create(struct radeon_device *rdev,
                ret = -ENOMEM;
                goto out_unref;
        }
+       ret = radeon_object_pin(robj, RADEON_GEM_DOMAIN_VRAM, &fb_gpuaddr);
+       if (ret) {
+               printk(KERN_ERR "failed to pin framebuffer\n");
+               ret = -ENOMEM;
+               goto out_unref;
+       }
 
        list_add(&fb->filp_head, &rdev->ddev->mode_config.fb_kernel_list);
 
        rfb = to_radeon_framebuffer(fb);
        *rfb_p = rfb;
        rdev->fbdev_rfb = rfb;
+       rdev->fbdev_robj = robj;
 
        info = framebuffer_alloc(sizeof(struct radeon_fb_device), device);
        if (info == NULL) {
@@ -541,13 +551,13 @@ int radeonfb_create(struct radeon_device *rdev,
        info->fix.xpanstep = 1; /* doing it in hw */
        info->fix.ypanstep = 1; /* doing it in hw */
        info->fix.ywrapstep = 0;
-       info->fix.accel = FB_ACCEL_I830;
+       info->fix.accel = FB_ACCEL_NONE;
        info->fix.type_aux = 0;
        info->flags = FBINFO_DEFAULT;
        info->fbops = &radeonfb_ops;
        info->fix.line_length = fb->pitch;
-       info->screen_base = fbptr;
-       info->fix.smem_start = (unsigned long)fbptr;
+       tmp = fb_gpuaddr - rdev->mc.vram_location;
+       info->fix.smem_start = rdev->mc.aper_base + tmp;
        info->fix.smem_len = size;
        info->screen_base = fbptr;
        info->screen_size = size;
@@ -562,8 +572,8 @@ int radeonfb_create(struct radeon_device *rdev,
        info->var.width = -1;
        info->var.xres = fb_width;
        info->var.yres = fb_height;
-       info->fix.mmio_start = pci_resource_start(rdev->pdev, 2);
-       info->fix.mmio_len = pci_resource_len(rdev->pdev, 2);
+       info->fix.mmio_start = 0;
+       info->fix.mmio_len = 0;
        info->pixmap.size = 64*1024;
        info->pixmap.buf_align = 8;
        info->pixmap.access_align = 32;
@@ -644,7 +654,7 @@ out_unref:
        if (robj) {
                radeon_object_kunmap(robj);
        }
-       if (ret) {
+       if (fb && ret) {
                list_del(&fb->filp_head);
                drm_gem_object_unreference(gobj);
                drm_framebuffer_cleanup(fb);
@@ -813,6 +823,7 @@ int radeonfb_remove(struct drm_device *dev, struct drm_framebuffer *fb)
                robj = rfb->obj->driver_private;
                unregister_framebuffer(info);
                radeon_object_kunmap(robj);
+               radeon_object_unpin(robj);
                framebuffer_release(info);
        }
 
index 983e8df..bac0d06 100644 (file)
@@ -223,7 +223,6 @@ int radeon_object_pin(struct radeon_object *robj, uint32_t domain,
 {
        uint32_t flags;
        uint32_t tmp;
-       void *fbptr;
        int r;
 
        flags = radeon_object_flags_from_domain(domain);
@@ -242,10 +241,6 @@ int radeon_object_pin(struct radeon_object *robj, uint32_t domain,
                DRM_ERROR("radeon: failed to reserve object for pinning it.\n");
                return r;
        }
-       if (robj->rdev->fbdev_robj == robj) {
-               mutex_lock(&robj->rdev->fbdev_info->lock);
-               radeon_object_kunmap(robj);
-       }
        tmp = robj->tobj.mem.placement;
        ttm_flag_masked(&tmp, flags, TTM_PL_MASK_MEM);
        robj->tobj.proposed_placement = tmp | TTM_PL_FLAG_NO_EVICT | TTM_PL_MASK_CACHING;
@@ -261,23 +256,12 @@ int radeon_object_pin(struct radeon_object *robj, uint32_t domain,
                DRM_ERROR("radeon: failed to pin object.\n");
        }
        radeon_object_unreserve(robj);
-       if (robj->rdev->fbdev_robj == robj) {
-               if (!r) {
-                       r = radeon_object_kmap(robj, &fbptr);
-               }
-               if (!r) {
-                       robj->rdev->fbdev_info->screen_base = fbptr;
-                       robj->rdev->fbdev_info->fix.smem_start = (unsigned long)fbptr;
-               }
-               mutex_unlock(&robj->rdev->fbdev_info->lock);
-       }
        return r;
 }
 
 void radeon_object_unpin(struct radeon_object *robj)
 {
        uint32_t flags;
-       void *fbptr;
        int r;
 
        spin_lock(&robj->tobj.lock);
@@ -297,10 +281,6 @@ void radeon_object_unpin(struct radeon_object *robj)
                DRM_ERROR("radeon: failed to reserve object for unpinning it.\n");
                return;
        }
-       if (robj->rdev->fbdev_robj == robj) {
-               mutex_lock(&robj->rdev->fbdev_info->lock);
-               radeon_object_kunmap(robj);
-       }
        flags = robj->tobj.mem.placement;
        robj->tobj.proposed_placement = flags & ~TTM_PL_FLAG_NO_EVICT;
        r = ttm_buffer_object_validate(&robj->tobj,
@@ -310,16 +290,6 @@ void radeon_object_unpin(struct radeon_object *robj)
                DRM_ERROR("radeon: failed to unpin buffer.\n");
        }
        radeon_object_unreserve(robj);
-       if (robj->rdev->fbdev_robj == robj) {
-               if (!r) {
-                       r = radeon_object_kmap(robj, &fbptr);
-               }
-               if (!r) {
-                       robj->rdev->fbdev_info->screen_base = fbptr;
-                       robj->rdev->fbdev_info->fix.smem_start = (unsigned long)fbptr;
-               }
-               mutex_unlock(&robj->rdev->fbdev_info->lock);
-       }
 }
 
 int radeon_object_wait(struct radeon_object *robj)
index 517c845..bdec583 100644 (file)
@@ -34,7 +34,6 @@
 #include <linux/highmem.h>
 #include <linux/wait.h>
 #include <linux/vmalloc.h>
-#include <linux/version.h>
 #include <linux/module.h>
 
 void ttm_bo_free_old_node(struct ttm_buffer_object *bo)
index 27b146c..40b7503 100644 (file)
@@ -32,7 +32,6 @@
 #include <ttm/ttm_bo_driver.h>
 #include <ttm/ttm_placement.h>
 #include <linux/mm.h>
-#include <linux/version.h>
 #include <linux/rbtree.h>
 #include <linux/module.h>
 #include <linux/uaccess.h>
index 0331fa7..75dc8bd 100644 (file)
@@ -28,7 +28,6 @@
  * Authors: Thomas Hellstrom <thellstrom-at-vmware-dot-com>
  */
 
-#include <linux/version.h>
 #include <linux/vmalloc.h>
 #include <linux/sched.h>
 #include <linux/highmem.h>
index aa87b6a..8206442 100644 (file)
@@ -328,6 +328,7 @@ config I2C_DAVINCI
 
 config I2C_DESIGNWARE
        tristate "Synopsys DesignWare"
+       depends on HAVE_CLK
        help
          If you say yes to this option, support will be included for the
          Synopsys DesignWare I2C adapter. Only master mode is supported.
index bd066bb..09f98ed 100644 (file)
@@ -135,6 +135,7 @@ static int __devinit cs5520_init_one(struct pci_dev *dev, const struct pci_devic
 
        ide_pci_setup_ports(dev, d, &hw[0], &hws[0]);
        hw[0].irq = 14;
+       hw[1].irq = 15;
 
        return ide_host_add(d, hws, 2, NULL);
 }
index 77f79d2..c509c99 100644 (file)
@@ -92,6 +92,11 @@ int ide_acpi_init(void)
        return 0;
 }
 
+bool ide_port_acpi(ide_hwif_t *hwif)
+{
+       return ide_noacpi == 0 && hwif->acpidata;
+}
+
 /**
  * ide_get_dev_handle - finds acpi_handle and PCI device.function
  * @dev: device to locate
@@ -352,9 +357,6 @@ int ide_acpi_exec_tfs(ide_drive_t *drive)
        unsigned long   gtf_address;
        unsigned long   obj_loc;
 
-       if (ide_noacpi)
-               return 0;
-
        DEBPRINT("call get_GTF, drive=%s port=%d\n", drive->name, drive->dn);
 
        ret = do_drive_get_GTF(drive, &gtf_length, &gtf_address, &obj_loc);
@@ -389,16 +391,6 @@ void ide_acpi_get_timing(ide_hwif_t *hwif)
        struct acpi_buffer      output;
        union acpi_object       *out_obj;
 
-       if (ide_noacpi)
-               return;
-
-       DEBPRINT("ENTER:\n");
-
-       if (!hwif->acpidata) {
-               DEBPRINT("no ACPI data for %s\n", hwif->name);
-               return;
-       }
-
        /* Setting up output buffer for _GTM */
        output.length = ACPI_ALLOCATE_BUFFER;
        output.pointer = NULL;  /* ACPI-CA sets this; save/free it later */
@@ -479,16 +471,6 @@ void ide_acpi_push_timing(ide_hwif_t *hwif)
        struct ide_acpi_drive_link      *master = &hwif->acpidata->master;
        struct ide_acpi_drive_link      *slave = &hwif->acpidata->slave;
 
-       if (ide_noacpi)
-               return;
-
-       DEBPRINT("ENTER:\n");
-
-       if (!hwif->acpidata) {
-               DEBPRINT("no ACPI data for %s\n", hwif->name);
-               return;
-       }
-
        /* Give the GTM buffer + drive Identify data to the channel via the
         * _STM method: */
        /* setup input parameters buffer for _STM */
@@ -527,16 +509,11 @@ void ide_acpi_set_state(ide_hwif_t *hwif, int on)
        ide_drive_t *drive;
        int i;
 
-       if (ide_noacpi || ide_noacpi_psx)
+       if (ide_noacpi_psx)
                return;
 
        DEBPRINT("ENTER:\n");
 
-       if (!hwif->acpidata) {
-               DEBPRINT("no ACPI data for %s\n", hwif->name);
-               return;
-       }
-
        /* channel first and then drives for power on and verse versa for power off */
        if (on)
                acpi_bus_set_power(hwif->acpidata->obj_handle, ACPI_STATE_D0);
@@ -616,7 +593,7 @@ void ide_acpi_port_init_devices(ide_hwif_t *hwif)
                                 drive->name, err);
        }
 
-       if (!ide_acpionboot) {
+       if (ide_noacpi || ide_acpionboot == 0) {
                DEBPRINT("ACPI methods disabled on boot\n");
                return;
        }
index 4a19686..6a9a769 100644 (file)
@@ -592,9 +592,19 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
                        }
                } else if (!blk_pc_request(rq)) {
                        ide_cd_request_sense_fixup(drive, cmd);
-                       /* complain if we still have data left to transfer */
+
                        uptodate = cmd->nleft ? 0 : 1;
-                       if (uptodate == 0)
+
+                       /*
+                        * suck out the remaining bytes from the drive in an
+                        * attempt to complete the data xfer. (see BZ#13399)
+                        */
+                       if (!(stat & ATA_ERR) && !uptodate && thislen) {
+                               ide_pio_bytes(drive, cmd, write, thislen);
+                               uptodate = cmd->nleft ? 0 : 1;
+                       }
+
+                       if (!uptodate)
                                rq->cmd_flags |= REQ_FAILED;
                }
                goto out_end;
@@ -876,9 +886,12 @@ static int cdrom_read_capacity(ide_drive_t *drive, unsigned long *capacity,
                return stat;
 
        /*
-        * Sanity check the given block size
+        * Sanity check the given block size, in so far as making
+        * sure the sectors_per_frame we give to the caller won't
+        * end up being bogus.
         */
        blocklen = be32_to_cpu(capbuf.blocklen);
+       blocklen = (blocklen >> SECTOR_BITS) << SECTOR_BITS;
        switch (blocklen) {
        case 512:
        case 1024:
@@ -886,10 +899,9 @@ static int cdrom_read_capacity(ide_drive_t *drive, unsigned long *capacity,
        case 4096:
                break;
        default:
-               printk(KERN_ERR PFX "%s: weird block size %u\n",
+               printk_once(KERN_ERR PFX "%s: weird block size %u; "
+                               "setting default block size to 2048\n",
                                drive->name, blocklen);
-               printk(KERN_ERR PFX "%s: default to 2kb block size\n",
-                               drive->name);
                blocklen = 2048;
                break;
        }
index 5bf958e..1099bf7 100644 (file)
@@ -183,6 +183,6 @@ ide_startstop_t ide_do_devset(ide_drive_t *drive, struct request *rq)
        err = setfunc(drive, *(int *)&rq->cmd[1]);
        if (err)
                rq->errors = err;
-       ide_complete_rq(drive, err, ide_rq_bytes(rq));
+       ide_complete_rq(drive, err, blk_rq_bytes(rq));
        return ide_stopped;
 }
index 219e6fb..ee58c88 100644 (file)
@@ -361,9 +361,6 @@ static int ide_tune_dma(ide_drive_t *drive)
        if (__ide_dma_bad_drive(drive))
                return 0;
 
-       if (ide_id_dma_bug(drive))
-               return 0;
-
        if (hwif->host_flags & IDE_HFLAG_TRUST_BIOS_FOR_DMA)
                return config_drive_for_dma(drive);
 
@@ -394,24 +391,6 @@ static int ide_dma_check(ide_drive_t *drive)
        return -1;
 }
 
-int ide_id_dma_bug(ide_drive_t *drive)
-{
-       u16 *id = drive->id;
-
-       if (id[ATA_ID_FIELD_VALID] & 4) {
-               if ((id[ATA_ID_UDMA_MODES] >> 8) &&
-                   (id[ATA_ID_MWDMA_MODES] >> 8))
-                       goto err_out;
-       } else if ((id[ATA_ID_MWDMA_MODES] >> 8) &&
-                  (id[ATA_ID_SWDMA_MODES] >> 8))
-               goto err_out;
-
-       return 0;
-err_out:
-       printk(KERN_ERR "%s: bad DMA info in identify block\n", drive->name);
-       return 1;
-}
-
 int ide_set_dma(ide_drive_t *drive)
 {
        int rc;
index 2b91419..e9abf2c 100644 (file)
@@ -149,7 +149,7 @@ static inline void ide_complete_drive_reset(ide_drive_t *drive, int err)
        if (rq && blk_special_request(rq) && rq->cmd[0] == REQ_DRIVE_RESET) {
                if (err <= 0 && rq->errors == 0)
                        rq->errors = -EIO;
-               ide_complete_rq(drive, err ? err : 0, ide_rq_bytes(rq));
+               ide_complete_rq(drive, err ? err : 0, blk_rq_bytes(rq));
        }
 }
 
index 8b3f204..fefbdfc 100644 (file)
@@ -293,7 +293,7 @@ out_end:
        drive->failed_pc = NULL;
        if (blk_fs_request(rq) == 0 && rq->errors == 0)
                rq->errors = -EIO;
-       ide_complete_rq(drive, -EIO, ide_rq_bytes(rq));
+       ide_complete_rq(drive, -EIO, blk_rq_bytes(rq));
        return ide_stopped;
 }
 
index 1059f80..d5f3c77 100644 (file)
@@ -112,16 +112,6 @@ void ide_complete_cmd(ide_drive_t *drive, struct ide_cmd *cmd, u8 stat, u8 err)
        }
 }
 
-/* obsolete, blk_rq_bytes() should be used instead */
-unsigned int ide_rq_bytes(struct request *rq)
-{
-       if (blk_pc_request(rq))
-               return blk_rq_bytes(rq);
-       else
-               return blk_rq_cur_sectors(rq) << 9;
-}
-EXPORT_SYMBOL_GPL(ide_rq_bytes);
-
 int ide_complete_rq(ide_drive_t *drive, int error, unsigned int nr_bytes)
 {
        ide_hwif_t *hwif = drive->hwif;
@@ -152,14 +142,14 @@ void ide_kill_rq(ide_drive_t *drive, struct request *rq)
 
        if ((media == ide_floppy || media == ide_tape) && drv_req) {
                rq->errors = 0;
-               ide_complete_rq(drive, 0, blk_rq_bytes(rq));
        } else {
                if (media == ide_tape)
                        rq->errors = IDE_DRV_ERROR_GENERAL;
                else if (blk_fs_request(rq) == 0 && rq->errors == 0)
                        rq->errors = -EIO;
-               ide_complete_rq(drive, -EIO, ide_rq_bytes(rq));
        }
+
+       ide_complete_rq(drive, -EIO, blk_rq_bytes(rq));
 }
 
 static void ide_tf_set_specify_cmd(ide_drive_t *drive, struct ide_taskfile *tf)
@@ -476,10 +466,14 @@ void do_ide_request(struct request_queue *q)
 
        if (!ide_lock_port(hwif)) {
                ide_hwif_t *prev_port;
-
-               WARN_ON_ONCE(hwif->rq);
 repeat:
                prev_port = hwif->host->cur_port;
+
+               if (drive->dev_flags & IDE_DFLAG_BLOCKED)
+                       rq = hwif->rq;
+               else
+                       WARN_ON_ONCE(hwif->rq);
+
                if (drive->dev_flags & IDE_DFLAG_SLEEPING &&
                    time_after(drive->sleep, jiffies)) {
                        ide_unlock_port(hwif);
@@ -506,43 +500,29 @@ repeat:
                hwif->cur_dev = drive;
                drive->dev_flags &= ~(IDE_DFLAG_SLEEPING | IDE_DFLAG_PARKED);
 
-               spin_unlock_irq(&hwif->lock);
-               spin_lock_irq(q->queue_lock);
-               /*
-                * we know that the queue isn't empty, but this can happen
-                * if the q->prep_rq_fn() decides to kill a request
-                */
-               if (!rq)
+               if (rq == NULL) {
+                       spin_unlock_irq(&hwif->lock);
+                       spin_lock_irq(q->queue_lock);
+                       /*
+                        * we know that the queue isn't empty, but this can
+                        * happen if ->prep_rq_fn() decides to kill a request
+                        */
                        rq = blk_fetch_request(drive->queue);
+                       spin_unlock_irq(q->queue_lock);
+                       spin_lock_irq(&hwif->lock);
 
-               spin_unlock_irq(q->queue_lock);
-               spin_lock_irq(&hwif->lock);
-
-               if (!rq) {
-                       ide_unlock_port(hwif);
-                       goto out;
+                       if (rq == NULL) {
+                               ide_unlock_port(hwif);
+                               goto out;
+                       }
                }
 
                /*
                 * Sanity: don't accept a request that isn't a PM request
-                * if we are currently power managed. This is very important as
-                * blk_stop_queue() doesn't prevent the blk_fetch_request()
-                * above to return us whatever is in the queue. Since we call
-                * ide_do_request() ourselves, we end up taking requests while
-                * the queue is blocked...
-                * 
-                * We let requests forced at head of queue with ide-preempt
-                * though. I hope that doesn't happen too much, hopefully not
-                * unless the subdriver triggers such a thing in its own PM
-                * state machine.
+                * if we are currently power managed.
                 */
-               if ((drive->dev_flags & IDE_DFLAG_BLOCKED) &&
-                   blk_pm_request(rq) == 0 &&
-                   (rq->cmd_flags & REQ_PREEMPT) == 0) {
-                       /* there should be no pending command at this point */
-                       ide_unlock_port(hwif);
-                       goto plug_device;
-               }
+               BUG_ON((drive->dev_flags & IDE_DFLAG_BLOCKED) &&
+                      blk_pm_request(rq) == 0);
 
                hwif->rq = rq;
 
index 82f252c..e246d3d 100644 (file)
@@ -64,7 +64,8 @@ static int ide_get_identity_ioctl(ide_drive_t *drive, unsigned int cmd,
                goto out;
        }
 
-       id = kmalloc(size, GFP_KERNEL);
+       /* ata_id_to_hd_driveid() relies on 'id' to be fully allocated. */
+       id = kmalloc(ATA_ID_WORDS * 2, GFP_KERNEL);
        if (id == NULL) {
                rc = -ENOMEM;
                goto out;
index fa04715..2892b24 100644 (file)
@@ -210,6 +210,7 @@ EXPORT_SYMBOL_GPL(ide_in_drive_list);
  */
 static const struct drive_list_entry ivb_list[] = {
        { "QUANTUM FIREBALLlct10 05"    , "A03.0900"    },
+       { "QUANTUM FIREBALLlct20 30"    , "APL.0900"    },
        { "TSSTcorp CDDVDW SH-S202J"    , "SB00"        },
        { "TSSTcorp CDDVDW SH-S202J"    , "SB01"        },
        { "TSSTcorp CDDVDW SH-S202N"    , "SB00"        },
@@ -329,9 +330,6 @@ int ide_driveid_update(ide_drive_t *drive)
 
        kfree(id);
 
-       if ((drive->dev_flags & IDE_DFLAG_USING_DMA) && ide_id_dma_bug(drive))
-               ide_dma_off(drive);
-
        return 1;
 out_err:
        if (rc == 2)
index c14ca14..ad7be26 100644 (file)
@@ -10,9 +10,11 @@ int generic_ide_suspend(struct device *dev, pm_message_t mesg)
        struct request_pm_state rqpm;
        int ret;
 
-       /* call ACPI _GTM only once */
-       if ((drive->dn & 1) == 0 || pair == NULL)
-               ide_acpi_get_timing(hwif);
+       if (ide_port_acpi(hwif)) {
+               /* call ACPI _GTM only once */
+               if ((drive->dn & 1) == 0 || pair == NULL)
+                       ide_acpi_get_timing(hwif);
+       }
 
        memset(&rqpm, 0, sizeof(rqpm));
        rq = blk_get_request(drive->queue, READ, __GFP_WAIT);
@@ -26,9 +28,11 @@ int generic_ide_suspend(struct device *dev, pm_message_t mesg)
        ret = blk_execute_rq(drive->queue, NULL, rq, 0);
        blk_put_request(rq);
 
-       /* call ACPI _PS3 only after both devices are suspended */
-       if (ret == 0 && ((drive->dn & 1) || pair == NULL))
-               ide_acpi_set_state(hwif, 0);
+       if (ret == 0 && ide_port_acpi(hwif)) {
+               /* call ACPI _PS3 only after both devices are suspended */
+               if ((drive->dn & 1) || pair == NULL)
+                       ide_acpi_set_state(hwif, 0);
+       }
 
        return ret;
 }
@@ -42,13 +46,15 @@ int generic_ide_resume(struct device *dev)
        struct request_pm_state rqpm;
        int err;
 
-       /* call ACPI _PS0 / _STM only once */
-       if ((drive->dn & 1) == 0 || pair == NULL) {
-               ide_acpi_set_state(hwif, 1);
-               ide_acpi_push_timing(hwif);
-       }
+       if (ide_port_acpi(hwif)) {
+               /* call ACPI _PS0 / _STM only once */
+               if ((drive->dn & 1) == 0 || pair == NULL) {
+                       ide_acpi_set_state(hwif, 1);
+                       ide_acpi_push_timing(hwif);
+               }
 
-       ide_acpi_exec_tfs(drive);
+               ide_acpi_exec_tfs(drive);
+       }
 
        memset(&rqpm, 0, sizeof(rqpm));
        rq = blk_get_request(drive->queue, READ, __GFP_WAIT);
index 51af4ee..1bb106f 100644 (file)
@@ -818,6 +818,24 @@ static int ide_port_setup_devices(ide_hwif_t *hwif)
        return j;
 }
 
+static void ide_host_enable_irqs(struct ide_host *host)
+{
+       ide_hwif_t *hwif;
+       int i;
+
+       ide_host_for_each_port(i, hwif, host) {
+               if (hwif == NULL)
+                       continue;
+
+               /* clear any pending IRQs */
+               hwif->tp_ops->read_status(hwif);
+
+               /* unmask IRQs */
+               if (hwif->io_ports.ctl_addr)
+                       hwif->tp_ops->write_devctl(hwif, ATA_DEVCTL_OBS);
+       }
+}
+
 /*
  * This routine sets up the IRQ for an IDE interface.
  */
@@ -831,9 +849,6 @@ static int init_irq (ide_hwif_t *hwif)
        if (irq_handler == NULL)
                irq_handler = ide_intr;
 
-       if (io_ports->ctl_addr)
-               hwif->tp_ops->write_devctl(hwif, ATA_DEVCTL_OBS);
-
        if (request_irq(hwif->irq, irq_handler, sa, hwif->name, hwif))
                goto out_up;
 
@@ -1404,6 +1419,8 @@ int ide_host_register(struct ide_host *host, const struct ide_port_info *d,
                        ide_port_tune_devices(hwif);
        }
 
+       ide_host_enable_irqs(host);
+
        ide_host_for_each_port(i, hwif, host) {
                if (hwif == NULL)
                        continue;
index 0384144..14045a7 100644 (file)
@@ -132,7 +132,7 @@ static int ieee802154_fake_xmit(struct sk_buff *skb, struct net_device *dev)
 
        /* FIXME: do hardware work here ... */
 
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 
index 2adf9cb..d114d3a 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  Cobalt button interface driver.
  *
- *  Copyright (C) 2007-2008  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *  Copyright (C) 2007-2008  Yoichi Yuasa <yuasa@linux-mips.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
@@ -148,7 +148,7 @@ static int __devexit cobalt_buttons_remove(struct platform_device *pdev)
        return 0;
 }
 
-MODULE_AUTHOR("Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>");
+MODULE_AUTHOR("Yoichi Yuasa <yuasa@linux-mips.org>");
 MODULE_DESCRIPTION("Cobalt button interface driver");
 MODULE_LICENSE("GPL");
 /* work with hotplug and coldplug */
index 579974c..c73004b 100644 (file)
@@ -148,7 +148,7 @@ net_send_packet(struct sk_buff *skb, struct net_device *dev)
        if (lp->sk_count <= 3) {
                schedule_work(&((hysdn_card *) dev->ml_priv)->irq_queue);
        }
-       return (0);             /* success */
+       return NETDEV_TX_OK;    /* success */
 }                              /* net_send_packet */
 
 
index de4aad0..57bf4bf 100644 (file)
@@ -1051,12 +1051,12 @@ isdn_net_xmit(struct net_device *ndev, struct sk_buff *skb)
        isdn_net_dev *nd;
        isdn_net_local *slp;
        isdn_net_local *lp = (isdn_net_local *) netdev_priv(ndev);
-       int retv = 0;
+       int retv = NETDEV_TX_OK;
 
        if (((isdn_net_local *) netdev_priv(ndev))->master) {
                printk("isdn BUG at %s:%d!\n", __FILE__, __LINE__);
                dev_kfree_skb(skb);
-               return 0;
+               return NETDEV_TX_OK;
        }
 
        /* For the other encaps the header has already been built */
@@ -1202,7 +1202,7 @@ isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev)
                        if (!(ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_AUTO)) {
                                isdn_net_unreachable(ndev, skb, "dial rejected: interface not in dialmode `auto'");
                                dev_kfree_skb(skb);
-                               return 0;
+                               return NETDEV_TX_OK;
                        }
                        if (lp->phone[1]) {
                                ulong flags;
@@ -1215,7 +1215,7 @@ isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev)
                                        if(time_before(jiffies, lp->dialwait_timer)) {
                                                isdn_net_unreachable(ndev, skb, "dial rejected: retry-time not reached");
                                                dev_kfree_skb(skb);
-                                               return 0;
+                                               return NETDEV_TX_OK;
                                        } else
                                                lp->dialwait_timer = 0;
                                }
@@ -1243,7 +1243,7 @@ isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev)
                                        isdn_net_unreachable(ndev, skb,
                                                           "No channel");
                                        dev_kfree_skb(skb);
-                                       return 0;
+                                       return NETDEV_TX_OK;
                                }
                                /* Log packet, which triggered dialing */
                                if (dev->net_verbose)
@@ -1258,7 +1258,7 @@ isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev)
                                                dev_kfree_skb(skb);
                                                isdn_net_unbind_channel(lp);
                                                spin_unlock_irqrestore(&dev->lock, flags);
-                                               return 0;       /* STN (skb to nirvana) ;) */
+                                               return NETDEV_TX_OK;    /* STN (skb to nirvana) ;) */
                                        }
 #ifdef CONFIG_IPPP_FILTER
                                        if (isdn_ppp_autodial_filter(skb, lp)) {
@@ -1267,7 +1267,7 @@ isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev)
                                                spin_unlock_irqrestore(&dev->lock, flags);
                                                isdn_net_unreachable(ndev, skb, "dial rejected: packet filtered");
                                                dev_kfree_skb(skb);
-                                               return 0;
+                                               return NETDEV_TX_OK;
                                        }
 #endif
                                        spin_unlock_irqrestore(&dev->lock, flags);
@@ -1285,7 +1285,7 @@ isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev)
                                isdn_net_unreachable(ndev, skb,
                                                     "No phone number");
                                dev_kfree_skb(skb);
-                               return 0;
+                               return NETDEV_TX_OK;
                        }
                } else {
                        /* Device is connected to an ISDN channel */ 
index aa30b5c..2d14b64 100644 (file)
@@ -1223,7 +1223,7 @@ isdn_ppp_xmit(struct sk_buff *skb, struct net_device *netdev)
        isdn_net_dev *nd;
        unsigned int proto = PPP_IP;     /* 0x21 */
        struct ippp_struct *ipt,*ipts;
-       int slot, retval = 0;
+       int slot, retval = NETDEV_TX_OK;
 
        mlp = (isdn_net_local *) netdev_priv(netdev);
        nd = mlp->netdev;       /* get master lp */
@@ -1240,7 +1240,7 @@ isdn_ppp_xmit(struct sk_buff *skb, struct net_device *netdev)
        if (!(ipts->pppcfg & SC_ENABLE_IP)) {   /* PPP connected ? */
                if (ipts->debug & 0x1)
                        printk(KERN_INFO "%s: IP frame delayed.\n", netdev->name);
-               retval = 1;
+               retval = NETDEV_TX_BUSY;
                goto out;
        }
 
@@ -1261,7 +1261,7 @@ isdn_ppp_xmit(struct sk_buff *skb, struct net_device *netdev)
        lp = isdn_net_get_locked_lp(nd);
        if (!lp) {
                printk(KERN_WARNING "%s: all channels busy - requeuing!\n", netdev->name);
-               retval = 1;
+               retval = NETDEV_TX_BUSY;
                goto out;
        }
        /* we have our lp locked from now on */
index 9b60b6b..7c8e712 100644 (file)
@@ -75,6 +75,7 @@ config LEDS_ALIX2
        depends on LEDS_CLASS && X86 && EXPERIMENTAL
        help
          This option enables support for the PCEngines ALIX.2 and ALIX.3 LEDs.
+         You have to set leds-alix2.force=1 for boards with Award BIOS.
 
 config LEDS_H1940
        tristate "LED Support for iPAQ H1940 device"
@@ -145,15 +146,16 @@ config LEDS_GPIO_OF
          of_platform devices.  For instance, LEDs which are listed in a "dts"
          file.
 
-config LEDS_LP5521
-       tristate "LED Support for the LP5521 LEDs"
+config LEDS_LP3944
+       tristate "LED Support for N.S. LP3944 (Fun Light) I2C chip"
        depends on LEDS_CLASS && I2C
        help
-         If you say 'Y' here you get support for the National Semiconductor
-         LP5521 LED driver used in n8x0 boards.
+    This option enables support for LEDs connected to the National
+    Semiconductor LP3944 Lighting Management Unit (LMU) also known as
+    Fun Light Chip.
 
-         This driver can be built as a module by choosing 'M'. The module
-         will be called leds-lp5521.
+         To compile this driver as a module, choose M here: the
+         module will be called leds-lp3944.
 
 config LEDS_CLEVO_MAIL
        tristate "Mail LED on Clevo notebook"
index 2d41c4d..e8cdcf7 100644 (file)
@@ -20,6 +20,7 @@ obj-$(CONFIG_LEDS_COBALT_RAQ)         += leds-cobalt-raq.o
 obj-$(CONFIG_LEDS_SUNFIRE)             += leds-sunfire.o
 obj-$(CONFIG_LEDS_PCA9532)             += leds-pca9532.o
 obj-$(CONFIG_LEDS_GPIO)                        += leds-gpio.o
+obj-$(CONFIG_LEDS_LP3944)              += leds-lp3944.o
 obj-$(CONFIG_LEDS_CLEVO_MAIL)          += leds-clevo-mail.o
 obj-$(CONFIG_LEDS_HP6XX)               += leds-hp6xx.o
 obj-$(CONFIG_LEDS_FSG)                 += leds-fsg.o
index ddbd773..731d4ee 100644 (file)
@@ -14,7 +14,7 @@
 
 static int force = 0;
 module_param(force, bool, 0444);
-MODULE_PARM_DESC(force, "Assume system has ALIX.2 style LEDs");
+MODULE_PARM_DESC(force, "Assume system has ALIX.2/ALIX.3 style LEDs");
 
 struct alix_led {
        struct led_classdev cdev;
@@ -155,6 +155,11 @@ static int __init alix_led_init(void)
                goto out;
        }
 
+       /* enable output on GPIO for LED 1,2,3 */
+       outl(1 << 6, 0x6104);
+       outl(1 << 9, 0x6184);
+       outl(1 << 11, 0x6184);
+
        pdev = platform_device_register_simple(KBUILD_MODNAME, -1, NULL, 0);
        if (!IS_ERR(pdev)) {
                ret = platform_driver_probe(&alix_led_driver, alix_led_probe);
index 4149ecb..779d7f2 100644 (file)
@@ -97,6 +97,10 @@ struct bd2802_led {
        enum led_ids                    led_id;
        enum led_colors                 color;
        enum led_bits                   state;
+
+       /* General attributes of RGB LEDs */
+       int                             wave_pattern;
+       int                             rgb_current;
 };
 
 
@@ -254,7 +258,7 @@ static void bd2802_set_on(struct bd2802_led *led, enum led_ids id,
                bd2802_reset_cancel(led);
 
        reg = bd2802_get_reg_addr(id, color, BD2802_REG_CURRENT1SETUP);
-       bd2802_write_byte(led->client, reg, BD2802_CURRENT_032);
+       bd2802_write_byte(led->client, reg, led->rgb_current);
        reg = bd2802_get_reg_addr(id, color, BD2802_REG_CURRENT2SETUP);
        bd2802_write_byte(led->client, reg, BD2802_CURRENT_000);
        reg = bd2802_get_reg_addr(id, color, BD2802_REG_WAVEPATTERN);
@@ -275,9 +279,9 @@ static void bd2802_set_blink(struct bd2802_led *led, enum led_ids id,
        reg = bd2802_get_reg_addr(id, color, BD2802_REG_CURRENT1SETUP);
        bd2802_write_byte(led->client, reg, BD2802_CURRENT_000);
        reg = bd2802_get_reg_addr(id, color, BD2802_REG_CURRENT2SETUP);
-       bd2802_write_byte(led->client, reg, BD2802_CURRENT_032);
+       bd2802_write_byte(led->client, reg, led->rgb_current);
        reg = bd2802_get_reg_addr(id, color, BD2802_REG_WAVEPATTERN);
-       bd2802_write_byte(led->client, reg, BD2802_PATTERN_HALF);
+       bd2802_write_byte(led->client, reg, led->wave_pattern);
 
        bd2802_enable(led, id);
        bd2802_update_state(led, id, color, BD2802_BLINK);
@@ -406,7 +410,7 @@ static void bd2802_enable_adv_conf(struct bd2802_led *led)
                ret = device_create_file(&led->client->dev,
                                                bd2802_addr_attributes[i]);
                if (ret) {
-                       dev_err(&led->client->dev, "failed to sysfs file %s\n",
+                       dev_err(&led->client->dev, "failed: sysfs file %s\n",
                                        bd2802_addr_attributes[i]->attr.name);
                        goto failed_remove_files;
                }
@@ -483,6 +487,52 @@ static struct device_attribute bd2802_adv_conf_attr = {
        .store = bd2802_store_adv_conf,
 };
 
+#define BD2802_CONTROL_ATTR(attr_name, name_str)                       \
+static ssize_t bd2802_show_##attr_name(struct device *dev,             \
+       struct device_attribute *attr, char *buf)                       \
+{                                                                      \
+       struct bd2802_led *led = i2c_get_clientdata(to_i2c_client(dev));\
+       ssize_t ret;                                                    \
+       down_read(&led->rwsem);                                         \
+       ret = sprintf(buf, "0x%02x\n", led->attr_name);                 \
+       up_read(&led->rwsem);                                           \
+       return ret;                                                     \
+}                                                                      \
+static ssize_t bd2802_store_##attr_name(struct device *dev,            \
+       struct device_attribute *attr, const char *buf, size_t count)   \
+{                                                                      \
+       struct bd2802_led *led = i2c_get_clientdata(to_i2c_client(dev));\
+       unsigned long val;                                              \
+       int ret;                                                        \
+       if (!count)                                                     \
+               return -EINVAL;                                         \
+       ret = strict_strtoul(buf, 16, &val);                            \
+       if (ret)                                                        \
+               return ret;                                             \
+       down_write(&led->rwsem);                                        \
+       led->attr_name = val;                                           \
+       up_write(&led->rwsem);                                          \
+       return count;                                                   \
+}                                                                      \
+static struct device_attribute bd2802_##attr_name##_attr = {           \
+       .attr = {                                                       \
+               .name = name_str,                                       \
+               .mode = 0644,                                           \
+               .owner = THIS_MODULE                                    \
+       },                                                              \
+       .show = bd2802_show_##attr_name,                                \
+       .store = bd2802_store_##attr_name,                              \
+};
+
+BD2802_CONTROL_ATTR(wave_pattern, "wave_pattern");
+BD2802_CONTROL_ATTR(rgb_current, "rgb_current");
+
+static struct device_attribute *bd2802_attributes[] = {
+       &bd2802_adv_conf_attr,
+       &bd2802_wave_pattern_attr,
+       &bd2802_rgb_current_attr,
+};
+
 static void bd2802_led_work(struct work_struct *work)
 {
        struct bd2802_led *led = container_of(work, struct bd2802_led, work);
@@ -538,7 +588,6 @@ static int bd2802_register_led_classdev(struct bd2802_led *led)
        led->cdev_led1r.brightness = LED_OFF;
        led->cdev_led1r.brightness_set = bd2802_set_led1r_brightness;
        led->cdev_led1r.blink_set = bd2802_set_led1r_blink;
-       led->cdev_led1r.flags |= LED_CORE_SUSPENDRESUME;
 
        ret = led_classdev_register(&led->client->dev, &led->cdev_led1r);
        if (ret < 0) {
@@ -551,7 +600,6 @@ static int bd2802_register_led_classdev(struct bd2802_led *led)
        led->cdev_led1g.brightness = LED_OFF;
        led->cdev_led1g.brightness_set = bd2802_set_led1g_brightness;
        led->cdev_led1g.blink_set = bd2802_set_led1g_blink;
-       led->cdev_led1g.flags |= LED_CORE_SUSPENDRESUME;
 
        ret = led_classdev_register(&led->client->dev, &led->cdev_led1g);
        if (ret < 0) {
@@ -564,7 +612,6 @@ static int bd2802_register_led_classdev(struct bd2802_led *led)
        led->cdev_led1b.brightness = LED_OFF;
        led->cdev_led1b.brightness_set = bd2802_set_led1b_brightness;
        led->cdev_led1b.blink_set = bd2802_set_led1b_blink;
-       led->cdev_led1b.flags |= LED_CORE_SUSPENDRESUME;
 
        ret = led_classdev_register(&led->client->dev, &led->cdev_led1b);
        if (ret < 0) {
@@ -577,7 +624,6 @@ static int bd2802_register_led_classdev(struct bd2802_led *led)
        led->cdev_led2r.brightness = LED_OFF;
        led->cdev_led2r.brightness_set = bd2802_set_led2r_brightness;
        led->cdev_led2r.blink_set = bd2802_set_led2r_blink;
-       led->cdev_led2r.flags |= LED_CORE_SUSPENDRESUME;
 
        ret = led_classdev_register(&led->client->dev, &led->cdev_led2r);
        if (ret < 0) {
@@ -590,7 +636,6 @@ static int bd2802_register_led_classdev(struct bd2802_led *led)
        led->cdev_led2g.brightness = LED_OFF;
        led->cdev_led2g.brightness_set = bd2802_set_led2g_brightness;
        led->cdev_led2g.blink_set = bd2802_set_led2g_blink;
-       led->cdev_led2g.flags |= LED_CORE_SUSPENDRESUME;
 
        ret = led_classdev_register(&led->client->dev, &led->cdev_led2g);
        if (ret < 0) {
@@ -640,7 +685,7 @@ static int __devinit bd2802_probe(struct i2c_client *client,
 {
        struct bd2802_led *led;
        struct bd2802_led_platform_data *pdata;
-       int ret;
+       int ret, i;
 
        led = kzalloc(sizeof(struct bd2802_led), GFP_KERNEL);
        if (!led) {
@@ -670,13 +715,20 @@ static int __devinit bd2802_probe(struct i2c_client *client,
        /* To save the power, reset BD2802 after detecting */
        gpio_set_value(led->pdata->reset_gpio, 0);
 
+       /* Default attributes */
+       led->wave_pattern = BD2802_PATTERN_HALF;
+       led->rgb_current = BD2802_CURRENT_032;
+
        init_rwsem(&led->rwsem);
 
-       ret = device_create_file(&client->dev, &bd2802_adv_conf_attr);
-       if (ret) {
-               dev_err(&client->dev, "failed to create sysfs file %s\n",
-                                       bd2802_adv_conf_attr.attr.name);
-               goto failed_free;
+       for (i = 0; i < ARRAY_SIZE(bd2802_attributes); i++) {
+               ret = device_create_file(&led->client->dev,
+                                               bd2802_attributes[i]);
+               if (ret) {
+                       dev_err(&led->client->dev, "failed: sysfs file %s\n",
+                                       bd2802_attributes[i]->attr.name);
+                       goto failed_unregister_dev_file;
+               }
        }
 
        ret = bd2802_register_led_classdev(led);
@@ -686,7 +738,8 @@ static int __devinit bd2802_probe(struct i2c_client *client,
        return 0;
 
 failed_unregister_dev_file:
-       device_remove_file(&client->dev, &bd2802_adv_conf_attr);
+       for (i--; i >= 0; i--)
+               device_remove_file(&led->client->dev, bd2802_attributes[i]);
 failed_free:
        i2c_set_clientdata(client, NULL);
        kfree(led);
@@ -697,12 +750,14 @@ failed_free:
 static int __exit bd2802_remove(struct i2c_client *client)
 {
        struct bd2802_led *led = i2c_get_clientdata(client);
+       int i;
 
-       bd2802_unregister_led_classdev(led);
        gpio_set_value(led->pdata->reset_gpio, 0);
+       bd2802_unregister_led_classdev(led);
        if (led->adf_on)
                bd2802_disable_adv_conf(led);
-       device_remove_file(&client->dev, &bd2802_adv_conf_attr);
+       for (i = 0; i < ARRAY_SIZE(bd2802_attributes); i++)
+               device_remove_file(&led->client->dev, bd2802_attributes[i]);
        i2c_set_clientdata(client, NULL);
        kfree(led);
 
@@ -723,8 +778,7 @@ static int bd2802_resume(struct i2c_client *client)
        struct bd2802_led *led = i2c_get_clientdata(client);
 
        if (!bd2802_is_all_off(led) || led->adf_on) {
-               gpio_set_value(led->pdata->reset_gpio, 1);
-               udelay(100);
+               bd2802_reset_cancel(led);
                bd2802_restore_state(led);
        }
 
@@ -762,4 +816,4 @@ module_exit(bd2802_exit);
 
 MODULE_AUTHOR("Kim Kyuwon <q1.kim@samsung.com>");
 MODULE_DESCRIPTION("BD2802 LED driver");
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
index ff0e8c3..5f1ce81 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  LEDs driver for the Cobalt Raq series.
  *
- *  Copyright (C) 2007  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *  Copyright (C) 2007  Yoichi Yuasa <yuasa@linux-mips.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
index d210905..6b06638 100644 (file)
@@ -76,7 +76,7 @@ static int __devinit create_gpio_led(const struct gpio_led *template,
        struct gpio_led_data *led_dat, struct device *parent,
        int (*blink_set)(unsigned, unsigned long *, unsigned long *))
 {
-       int ret;
+       int ret, state;
 
        /* skip leds that aren't available */
        if (!gpio_is_valid(template->gpio)) {
@@ -99,11 +99,15 @@ static int __devinit create_gpio_led(const struct gpio_led *template,
                led_dat->cdev.blink_set = gpio_blink_set;
        }
        led_dat->cdev.brightness_set = gpio_led_set;
-       led_dat->cdev.brightness = LED_OFF;
+       if (template->default_state == LEDS_GPIO_DEFSTATE_KEEP)
+               state = !!gpio_get_value(led_dat->gpio) ^ led_dat->active_low;
+       else
+               state = (template->default_state == LEDS_GPIO_DEFSTATE_ON);
+       led_dat->cdev.brightness = state ? LED_FULL : LED_OFF;
        if (!template->retain_state_suspended)
                led_dat->cdev.flags |= LED_CORE_SUSPENDRESUME;
 
-       ret = gpio_direction_output(led_dat->gpio, led_dat->active_low);
+       ret = gpio_direction_output(led_dat->gpio, led_dat->active_low ^ state);
        if (ret < 0)
                goto err;
 
@@ -129,7 +133,7 @@ static void delete_gpio_led(struct gpio_led_data *led)
 }
 
 #ifdef CONFIG_LEDS_GPIO_PLATFORM
-static int gpio_led_probe(struct platform_device *pdev)
+static int __devinit gpio_led_probe(struct platform_device *pdev)
 {
        struct gpio_led_platform_data *pdata = pdev->dev.platform_data;
        struct gpio_led_data *leds_data;
@@ -223,12 +227,22 @@ static int __devinit of_gpio_leds_probe(struct of_device *ofdev,
        memset(&led, 0, sizeof(led));
        for_each_child_of_node(np, child) {
                enum of_gpio_flags flags;
+               const char *state;
 
                led.gpio = of_get_gpio_flags(child, 0, &flags);
                led.active_low = flags & OF_GPIO_ACTIVE_LOW;
                led.name = of_get_property(child, "label", NULL) ? : child->name;
                led.default_trigger =
                        of_get_property(child, "linux,default-trigger", NULL);
+               state = of_get_property(child, "default-state", NULL);
+               if (state) {
+                       if (!strcmp(state, "keep"))
+                               led.default_state = LEDS_GPIO_DEFSTATE_KEEP;
+                       else if(!strcmp(state, "on"))
+                               led.default_state = LEDS_GPIO_DEFSTATE_ON;
+                       else
+                               led.default_state = LEDS_GPIO_DEFSTATE_OFF;
+               }
 
                ret = create_gpio_led(&led, &pdata->led_data[pdata->num_leds++],
                                      &ofdev->dev, NULL);
diff --git a/drivers/leds/leds-lp3944.c b/drivers/leds/leds-lp3944.c
new file mode 100644 (file)
index 0000000..5946208
--- /dev/null
@@ -0,0 +1,466 @@
+/*
+ * leds-lp3944.c - driver for National Semiconductor LP3944 Funlight Chip
+ *
+ * Copyright (C) 2009 Antonio Ospite <ospite@studenti.unina.it>
+ *
+ * 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.
+ *
+ */
+
+/*
+ * I2C driver for National Semiconductor LP3944 Funlight Chip
+ * http://www.national.com/pf/LP/LP3944.html
+ *
+ * This helper chip can drive up to 8 leds, with two programmable DIM modes;
+ * it could even be used as a gpio expander but this driver assumes it is used
+ * as a led controller.
+ *
+ * The DIM modes are used to set _blink_ patterns for leds, the pattern is
+ * specified supplying two parameters:
+ *   - period: from 0s to 1.6s
+ *   - duty cycle: percentage of the period the led is on, from 0 to 100
+ *
+ * LP3944 can be found on Motorola A910 smartphone, where it drives the rgb
+ * leds, the camera flash light and the displays backlights.
+ */
+
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/leds.h>
+#include <linux/mutex.h>
+#include <linux/workqueue.h>
+#include <linux/leds-lp3944.h>
+
+/* Read Only Registers */
+#define LP3944_REG_INPUT1     0x00 /* LEDs 0-7 InputRegister (Read Only) */
+#define LP3944_REG_REGISTER1  0x01 /* None (Read Only) */
+
+#define LP3944_REG_PSC0       0x02 /* Frequency Prescaler 0 (R/W) */
+#define LP3944_REG_PWM0       0x03 /* PWM Register 0 (R/W) */
+#define LP3944_REG_PSC1       0x04 /* Frequency Prescaler 1 (R/W) */
+#define LP3944_REG_PWM1       0x05 /* PWM Register 1 (R/W) */
+#define LP3944_REG_LS0        0x06 /* LEDs 0-3 Selector (R/W) */
+#define LP3944_REG_LS1        0x07 /* LEDs 4-7 Selector (R/W) */
+
+/* These registers are not used to control leds in LP3944, they can store
+ * arbitrary values which the chip will ignore.
+ */
+#define LP3944_REG_REGISTER8  0x08
+#define LP3944_REG_REGISTER9  0x09
+
+#define LP3944_DIM0 0
+#define LP3944_DIM1 1
+
+/* period in ms */
+#define LP3944_PERIOD_MIN 0
+#define LP3944_PERIOD_MAX 1600
+
+/* duty cycle is a percentage */
+#define LP3944_DUTY_CYCLE_MIN 0
+#define LP3944_DUTY_CYCLE_MAX 100
+
+#define ldev_to_led(c)       container_of(c, struct lp3944_led_data, ldev)
+
+/* Saved data */
+struct lp3944_led_data {
+       u8 id;
+       enum lp3944_type type;
+       enum lp3944_status status;
+       struct led_classdev ldev;
+       struct i2c_client *client;
+       struct work_struct work;
+};
+
+struct lp3944_data {
+       struct mutex lock;
+       struct i2c_client *client;
+       struct lp3944_led_data leds[LP3944_LEDS_MAX];
+};
+
+static int lp3944_reg_read(struct i2c_client *client, u8 reg, u8 *value)
+{
+       int tmp;
+
+       tmp = i2c_smbus_read_byte_data(client, reg);
+       if (tmp < 0)
+               return -EINVAL;
+
+       *value = tmp;
+
+       return 0;
+}
+
+static int lp3944_reg_write(struct i2c_client *client, u8 reg, u8 value)
+{
+       return i2c_smbus_write_byte_data(client, reg, value);
+}
+
+/**
+ * Set the period for DIM status
+ *
+ * @client: the i2c client
+ * @dim: either LP3944_DIM0 or LP3944_DIM1
+ * @period: period of a blink, that is a on/off cycle, expressed in ms.
+ */
+static int lp3944_dim_set_period(struct i2c_client *client, u8 dim, u16 period)
+{
+       u8 psc_reg;
+       u8 psc_value;
+       int err;
+
+       if (dim == LP3944_DIM0)
+               psc_reg = LP3944_REG_PSC0;
+       else if (dim == LP3944_DIM1)
+               psc_reg = LP3944_REG_PSC1;
+       else
+               return -EINVAL;
+
+       /* Convert period to Prescaler value */
+       if (period > LP3944_PERIOD_MAX)
+               return -EINVAL;
+
+       psc_value = (period * 255) / LP3944_PERIOD_MAX;
+
+       err = lp3944_reg_write(client, psc_reg, psc_value);
+
+       return err;
+}
+
+/**
+ * Set the duty cycle for DIM status
+ *
+ * @client: the i2c client
+ * @dim: either LP3944_DIM0 or LP3944_DIM1
+ * @duty_cycle: percentage of a period during which a led is ON
+ */
+static int lp3944_dim_set_dutycycle(struct i2c_client *client, u8 dim,
+                                   u8 duty_cycle)
+{
+       u8 pwm_reg;
+       u8 pwm_value;
+       int err;
+
+       if (dim == LP3944_DIM0)
+               pwm_reg = LP3944_REG_PWM0;
+       else if (dim == LP3944_DIM1)
+               pwm_reg = LP3944_REG_PWM1;
+       else
+               return -EINVAL;
+
+       /* Convert duty cycle to PWM value */
+       if (duty_cycle > LP3944_DUTY_CYCLE_MAX)
+               return -EINVAL;
+
+       pwm_value = (duty_cycle * 255) / LP3944_DUTY_CYCLE_MAX;
+
+       err = lp3944_reg_write(client, pwm_reg, pwm_value);
+
+       return err;
+}
+
+/**
+ * Set the led status
+ *
+ * @led: a lp3944_led_data structure
+ * @status: one of LP3944_LED_STATUS_OFF
+ *                 LP3944_LED_STATUS_ON
+ *                 LP3944_LED_STATUS_DIM0
+ *                 LP3944_LED_STATUS_DIM1
+ */
+static int lp3944_led_set(struct lp3944_led_data *led, u8 status)
+{
+       struct lp3944_data *data = i2c_get_clientdata(led->client);
+       u8 id = led->id;
+       u8 reg;
+       u8 val = 0;
+       int err;
+
+       dev_dbg(&led->client->dev, "%s: %s, status before normalization:%d\n",
+               __func__, led->ldev.name, status);
+
+       switch (id) {
+       case LP3944_LED0:
+       case LP3944_LED1:
+       case LP3944_LED2:
+       case LP3944_LED3:
+               reg = LP3944_REG_LS0;
+               break;
+       case LP3944_LED4:
+       case LP3944_LED5:
+       case LP3944_LED6:
+       case LP3944_LED7:
+               id -= LP3944_LED4;
+               reg = LP3944_REG_LS1;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       if (status > LP3944_LED_STATUS_DIM1)
+               return -EINVAL;
+
+       /* invert only 0 and 1, leave unchanged the other values,
+        * remember we are abusing status to set blink patterns
+        */
+       if (led->type == LP3944_LED_TYPE_LED_INVERTED && status < 2)
+               status = 1 - status;
+
+       mutex_lock(&data->lock);
+       lp3944_reg_read(led->client, reg, &val);
+
+       val &= ~(LP3944_LED_STATUS_MASK << (id << 1));
+       val |= (status << (id << 1));
+
+       dev_dbg(&led->client->dev, "%s: %s, reg:%d id:%d status:%d val:%#x\n",
+               __func__, led->ldev.name, reg, id, status, val);
+
+       /* set led status */
+       err = lp3944_reg_write(led->client, reg, val);
+       mutex_unlock(&data->lock);
+
+       return err;
+}
+
+static int lp3944_led_set_blink(struct led_classdev *led_cdev,
+                               unsigned long *delay_on,
+                               unsigned long *delay_off)
+{
+       struct lp3944_led_data *led = ldev_to_led(led_cdev);
+       u16 period;
+       u8 duty_cycle;
+       int err;
+
+       /* units are in ms */
+       if (*delay_on + *delay_off > LP3944_PERIOD_MAX)
+               return -EINVAL;
+
+       if (*delay_on == 0 && *delay_off == 0) {
+               /* Special case: the leds subsystem requires a default user
+                * friendly blink pattern for the LED.  Let's blink the led
+                * slowly (1Hz).
+                */
+               *delay_on = 500;
+               *delay_off = 500;
+       }
+
+       period = (*delay_on) + (*delay_off);
+
+       /* duty_cycle is the percentage of period during which the led is ON */
+       duty_cycle = 100 * (*delay_on) / period;
+
+       /* invert duty cycle for inverted leds, this has the same effect of
+        * swapping delay_on and delay_off
+        */
+       if (led->type == LP3944_LED_TYPE_LED_INVERTED)
+               duty_cycle = 100 - duty_cycle;
+
+       /* NOTE: using always the first DIM mode, this means that all leds
+        * will have the same blinking pattern.
+        *
+        * We could find a way later to have two leds blinking in hardware
+        * with different patterns at the same time, falling back to software
+        * control for the other ones.
+        */
+       err = lp3944_dim_set_period(led->client, LP3944_DIM0, period);
+       if (err)
+               return err;
+
+       err = lp3944_dim_set_dutycycle(led->client, LP3944_DIM0, duty_cycle);
+       if (err)
+               return err;
+
+       dev_dbg(&led->client->dev, "%s: OK hardware accelerated blink!\n",
+               __func__);
+
+       led->status = LP3944_LED_STATUS_DIM0;
+       schedule_work(&led->work);
+
+       return 0;
+}
+
+static void lp3944_led_set_brightness(struct led_classdev *led_cdev,
+                                     enum led_brightness brightness)
+{
+       struct lp3944_led_data *led = ldev_to_led(led_cdev);
+
+       dev_dbg(&led->client->dev, "%s: %s, %d\n",
+               __func__, led_cdev->name, brightness);
+
+       led->status = brightness;
+       schedule_work(&led->work);
+}
+
+static void lp3944_led_work(struct work_struct *work)
+{
+       struct lp3944_led_data *led;
+
+       led = container_of(work, struct lp3944_led_data, work);
+       lp3944_led_set(led, led->status);
+}
+
+static int lp3944_configure(struct i2c_client *client,
+                           struct lp3944_data *data,
+                           struct lp3944_platform_data *pdata)
+{
+       int i, err = 0;
+
+       for (i = 0; i < pdata->leds_size; i++) {
+               struct lp3944_led *pled = &pdata->leds[i];
+               struct lp3944_led_data *led = &data->leds[i];
+               led->client = client;
+               led->id = i;
+
+               switch (pled->type) {
+
+               case LP3944_LED_TYPE_LED:
+               case LP3944_LED_TYPE_LED_INVERTED:
+                       led->type = pled->type;
+                       led->status = pled->status;
+                       led->ldev.name = pled->name;
+                       led->ldev.max_brightness = 1;
+                       led->ldev.brightness_set = lp3944_led_set_brightness;
+                       led->ldev.blink_set = lp3944_led_set_blink;
+                       led->ldev.flags = LED_CORE_SUSPENDRESUME;
+
+                       INIT_WORK(&led->work, lp3944_led_work);
+                       err = led_classdev_register(&client->dev, &led->ldev);
+                       if (err < 0) {
+                               dev_err(&client->dev,
+                                       "couldn't register LED %s\n",
+                                       led->ldev.name);
+                               goto exit;
+                       }
+
+                       /* to expose the default value to userspace */
+                       led->ldev.brightness = led->status;
+
+                       /* Set the default led status */
+                       err = lp3944_led_set(led, led->status);
+                       if (err < 0) {
+                               dev_err(&client->dev,
+                                       "%s couldn't set STATUS %d\n",
+                                       led->ldev.name, led->status);
+                               goto exit;
+                       }
+                       break;
+
+               case LP3944_LED_TYPE_NONE:
+               default:
+                       break;
+
+               }
+       }
+       return 0;
+
+exit:
+       if (i > 0)
+               for (i = i - 1; i >= 0; i--)
+                       switch (pdata->leds[i].type) {
+
+                       case LP3944_LED_TYPE_LED:
+                       case LP3944_LED_TYPE_LED_INVERTED:
+                               led_classdev_unregister(&data->leds[i].ldev);
+                               cancel_work_sync(&data->leds[i].work);
+                               break;
+
+                       case LP3944_LED_TYPE_NONE:
+                       default:
+                               break;
+                       }
+
+       return err;
+}
+
+static int __devinit lp3944_probe(struct i2c_client *client,
+                                 const struct i2c_device_id *id)
+{
+       struct lp3944_platform_data *lp3944_pdata = client->dev.platform_data;
+       struct lp3944_data *data;
+
+       if (lp3944_pdata == NULL) {
+               dev_err(&client->dev, "no platform data\n");
+               return -EINVAL;
+       }
+
+       /* Let's see whether this adapter can support what we need. */
+       if (!i2c_check_functionality(client->adapter,
+                               I2C_FUNC_SMBUS_BYTE_DATA)) {
+               dev_err(&client->dev, "insufficient functionality!\n");
+               return -ENODEV;
+       }
+
+       data = kzalloc(sizeof(struct lp3944_data), GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+
+       data->client = client;
+       i2c_set_clientdata(client, data);
+
+       mutex_init(&data->lock);
+
+       dev_info(&client->dev, "lp3944 enabled\n");
+
+       lp3944_configure(client, data, lp3944_pdata);
+       return 0;
+}
+
+static int __devexit lp3944_remove(struct i2c_client *client)
+{
+       struct lp3944_platform_data *pdata = client->dev.platform_data;
+       struct lp3944_data *data = i2c_get_clientdata(client);
+       int i;
+
+       for (i = 0; i < pdata->leds_size; i++)
+               switch (data->leds[i].type) {
+               case LP3944_LED_TYPE_LED:
+               case LP3944_LED_TYPE_LED_INVERTED:
+                       led_classdev_unregister(&data->leds[i].ldev);
+                       cancel_work_sync(&data->leds[i].work);
+                       break;
+
+               case LP3944_LED_TYPE_NONE:
+               default:
+                       break;
+               }
+
+       kfree(data);
+       i2c_set_clientdata(client, NULL);
+
+       return 0;
+}
+
+/* lp3944 i2c driver struct */
+static const struct i2c_device_id lp3944_id[] = {
+       {"lp3944", 0},
+       {}
+};
+
+MODULE_DEVICE_TABLE(i2c, lp3944_id);
+
+static struct i2c_driver lp3944_driver = {
+       .driver   = {
+                  .name = "lp3944",
+       },
+       .probe    = lp3944_probe,
+       .remove   = __devexit_p(lp3944_remove),
+       .id_table = lp3944_id,
+};
+
+static int __init lp3944_module_init(void)
+{
+       return i2c_add_driver(&lp3944_driver);
+}
+
+static void __exit lp3944_module_exit(void)
+{
+       i2c_del_driver(&lp3944_driver);
+}
+
+module_init(lp3944_module_init);
+module_exit(lp3944_module_exit);
+
+MODULE_AUTHOR("Antonio Ospite <ospite@studenti.unina.it>");
+MODULE_DESCRIPTION("LP3944 Fun Light Chip");
+MODULE_LICENSE("GPL");
index 3937244..dba8921 100644 (file)
@@ -35,7 +35,7 @@ struct pca9532_data {
        struct pca9532_led leds[16];
        struct mutex update_lock;
        struct input_dev    *idev;
-       struct work_struct work;
+       struct work_struct work;
        u8 pwm[2];
        u8 psc[2];
 };
@@ -87,14 +87,14 @@ static int pca9532_calcpwm(struct i2c_client *client, int pwm, int blink,
        if (b > 0xFF)
                return -EINVAL;
        data->pwm[pwm] = b;
-       data->psc[pwm] = blink;
-       return 0;
+       data->psc[pwm] = blink;
+       return 0;
 }
 
 static int pca9532_setpwm(struct i2c_client *client, int pwm)
 {
-       struct pca9532_data *data = i2c_get_clientdata(client);
-       mutex_lock(&data->update_lock);
+       struct pca9532_data *data = i2c_get_clientdata(client);
+       mutex_lock(&data->update_lock);
        i2c_smbus_write_byte_data(client, PCA9532_REG_PWM(pwm),
                data->pwm[pwm]);
        i2c_smbus_write_byte_data(client, PCA9532_REG_PSC(pwm),
@@ -132,11 +132,11 @@ static void pca9532_set_brightness(struct led_classdev *led_cdev,
                led->state = PCA9532_ON;
        else {
                led->state = PCA9532_PWM0; /* Thecus: hardcode one pwm */
-               err = pca9532_calcpwm(led->client, 0, 0, value);
+               err = pca9532_calcpwm(led->client, 0, 0, value);
                if (err)
                        return; /* XXX: led api doesn't allow error code? */
        }
-       schedule_work(&led->work);
+       schedule_work(&led->work);
 }
 
 static int pca9532_set_blink(struct led_classdev *led_cdev,
@@ -145,7 +145,7 @@ static int pca9532_set_blink(struct led_classdev *led_cdev,
        struct pca9532_led *led = ldev_to_led(led_cdev);
        struct i2c_client *client = led->client;
        int psc;
-       int err = 0;
+       int err = 0;
 
        if (*delay_on == 0 && *delay_off == 0) {
        /* led subsystem ask us for a blink rate */
@@ -157,11 +157,11 @@ static int pca9532_set_blink(struct led_classdev *led_cdev,
 
        /* Thecus specific: only use PSC/PWM 0 */
        psc = (*delay_on * 152-1)/1000;
-       err = pca9532_calcpwm(client, 0, psc, led_cdev->brightness);
-       if (err)
-               return err;
-       schedule_work(&led->work);
-       return 0;
+       err = pca9532_calcpwm(client, 0, psc, led_cdev->brightness);
+       if (err)
+               return err;
+       schedule_work(&led->work);
+       return 0;
 }
 
 static int pca9532_event(struct input_dev *dev, unsigned int type,
@@ -178,15 +178,15 @@ static int pca9532_event(struct input_dev *dev, unsigned int type,
        else
                data->pwm[1] = 0;
 
-       schedule_work(&data->work);
+       schedule_work(&data->work);
 
-       return 0;
+       return 0;
 }
 
 static void pca9532_input_work(struct work_struct *work)
 {
-       struct pca9532_data *data;
-       data = container_of(work, struct pca9532_data, work);
+       struct pca9532_data *data;
+       data = container_of(work, struct pca9532_data, work);
        mutex_lock(&data->update_lock);
        i2c_smbus_write_byte_data(data->client, PCA9532_REG_PWM(1),
                data->pwm[1]);
@@ -195,11 +195,11 @@ static void pca9532_input_work(struct work_struct *work)
 
 static void pca9532_led_work(struct work_struct *work)
 {
-       struct pca9532_led *led;
-       led = container_of(work, struct pca9532_led, work);
-       if (led->state == PCA9532_PWM0)
-               pca9532_setpwm(led->client, 0);
-       pca9532_setled(led);
+       struct pca9532_led *led;
+       led = container_of(work, struct pca9532_led, work);
+       if (led->state == PCA9532_PWM0)
+               pca9532_setpwm(led->client, 0);
+       pca9532_setled(led);
 }
 
 static int pca9532_configure(struct i2c_client *client,
@@ -232,7 +232,7 @@ static int pca9532_configure(struct i2c_client *client,
                        led->ldev.brightness = LED_OFF;
                        led->ldev.brightness_set = pca9532_set_brightness;
                        led->ldev.blink_set = pca9532_set_blink;
-                       INIT_WORK(&led->work, pca9532_led_work);
+                       INIT_WORK(&led->work, pca9532_led_work);
                        err = led_classdev_register(&client->dev, &led->ldev);
                        if (err < 0) {
                                dev_err(&client->dev,
@@ -262,11 +262,11 @@ static int pca9532_configure(struct i2c_client *client,
                                                BIT_MASK(SND_TONE);
                        data->idev->event = pca9532_event;
                        input_set_drvdata(data->idev, data);
-                       INIT_WORK(&data->work, pca9532_input_work);
+                       INIT_WORK(&data->work, pca9532_input_work);
                        err = input_register_device(data->idev);
                        if (err) {
                                input_free_device(data->idev);
-                               cancel_work_sync(&data->work);
+                               cancel_work_sync(&data->work);
                                data->idev = NULL;
                                goto exit;
                        }
@@ -283,13 +283,13 @@ exit:
                                break;
                        case PCA9532_TYPE_LED:
                                led_classdev_unregister(&data->leds[i].ldev);
-                               cancel_work_sync(&data->leds[i].work);
+                               cancel_work_sync(&data->leds[i].work);
                                break;
                        case PCA9532_TYPE_N2100_BEEP:
                                if (data->idev != NULL) {
                                        input_unregister_device(data->idev);
                                        input_free_device(data->idev);
-                                       cancel_work_sync(&data->work);
+                                       cancel_work_sync(&data->work);
                                        data->idev = NULL;
                                }
                                break;
@@ -340,13 +340,13 @@ static int pca9532_remove(struct i2c_client *client)
                        break;
                case PCA9532_TYPE_LED:
                        led_classdev_unregister(&data->leds[i].ldev);
-                       cancel_work_sync(&data->leds[i].work);
+                       cancel_work_sync(&data->leds[i].work);
                        break;
                case PCA9532_TYPE_N2100_BEEP:
                        if (data->idev != NULL) {
                                input_unregister_device(data->idev);
                                input_free_device(data->idev);
-                               cancel_work_sync(&data->work);
+                               cancel_work_sync(&data->work);
                                data->idev = NULL;
                        }
                        break;
index d4e8979..9c31382 100644 (file)
@@ -82,7 +82,7 @@ struct lg_cpu {
 
 struct lg_eventfd {
        unsigned long addr;
-       struct file *event;
+       struct eventfd_ctx *event;
 };
 
 struct lg_eventfd_map {
index 32e2971..9f9a295 100644 (file)
@@ -50,7 +50,7 @@ static int add_eventfd(struct lguest *lg, unsigned long addr, int fd)
 
        /* Now append new entry. */
        new->map[new->num].addr = addr;
-       new->map[new->num].event = eventfd_fget(fd);
+       new->map[new->num].event = eventfd_ctx_fdget(fd);
        if (IS_ERR(new->map[new->num].event)) {
                kfree(new);
                return PTR_ERR(new->map[new->num].event);
@@ -357,7 +357,7 @@ static int close(struct inode *inode, struct file *file)
 
        /* Release any eventfds they registered. */
        for (i = 0; i < lg->eventfds->num; i++)
-               fput(lg->eventfds->map[i].event);
+               eventfd_ctx_put(lg->eventfds->map[i].event);
        kfree(lg->eventfds);
 
        /* If lg->dead doesn't contain an error code it will be NULL or a
index 6e149f4..a0f6838 100644 (file)
@@ -378,6 +378,17 @@ static struct macio_dev * macio_add_one_device(struct macio_chip *chip,
        dev->ofdev.dev.bus = &macio_bus_type;
        dev->ofdev.dev.release = macio_release_dev;
 
+#ifdef CONFIG_PCI
+       /* Set the DMA ops to the ones from the PCI device, this could be
+        * fishy if we didn't know that on PowerMac it's always direct ops
+        * or iommu ops that will work fine
+        */
+       dev->ofdev.dev.archdata.dma_ops =
+               chip->lbus.pdev->dev.archdata.dma_ops;
+       dev->ofdev.dev.archdata.dma_data =
+               chip->lbus.pdev->dev.archdata.dma_data;
+#endif /* CONFIG_PCI */
+
 #ifdef DEBUG
        printk("preparing mdev @%p, ofdev @%p, dev @%p, kobj @%p\n",
               dev, &dev->ofdev, &dev->ofdev.dev, &dev->ofdev.dev.kobj);
index c3ae515..3710ff8 100644 (file)
@@ -195,7 +195,7 @@ int dm_exception_store_create(struct dm_target *ti, int argc, char **argv,
                              struct dm_exception_store **store)
 {
        int r = 0;
-       struct dm_exception_store_type *type;
+       struct dm_exception_store_type *type = NULL;
        struct dm_exception_store *tmp_store;
        char persistent;
 
@@ -211,12 +211,15 @@ int dm_exception_store_create(struct dm_target *ti, int argc, char **argv,
        }
 
        persistent = toupper(*argv[1]);
-       if (persistent != 'P' && persistent != 'N') {
+       if (persistent == 'P')
+               type = get_type("P");
+       else if (persistent == 'N')
+               type = get_type("N");
+       else {
                ti->error = "Persistent flag is not P or N";
                return -EINVAL;
        }
 
-       type = get_type(&persistent);
        if (!type) {
                ti->error = "Exception store type not recognised";
                r = -EINVAL;
index 4899ebe..2cba557 100644 (file)
@@ -495,7 +495,7 @@ int dm_set_device_limits(struct dm_target *ti, struct dm_dev *dev,
                return 0;
        }
 
-       if (blk_stack_limits(limits, &q->limits, start) < 0)
+       if (blk_stack_limits(limits, &q->limits, start << 9) < 0)
                DMWARN("%s: target device %s is misaligned",
                       dm_device_name(ti->table->md), bdevname(bdev, b));
 
index 3c6d4ee..9acd54a 100644 (file)
@@ -1017,7 +1017,7 @@ static struct bio *split_bvec(struct bio *bio, sector_t sector,
        clone->bi_flags |= 1 << BIO_CLONED;
 
        if (bio_integrity(bio)) {
-               bio_integrity_clone(clone, bio, GFP_NOIO);
+               bio_integrity_clone(clone, bio, GFP_NOIO, bs);
                bio_integrity_trim(clone,
                                   bio_sector_offset(bio, idx, offset), len);
        }
@@ -1045,7 +1045,7 @@ static struct bio *clone_bio(struct bio *bio, sector_t sector,
        clone->bi_flags &= ~(1 << BIO_SEG_VALID);
 
        if (bio_integrity(bio)) {
-               bio_integrity_clone(clone, bio, GFP_NOIO);
+               bio_integrity_clone(clone, bio, GFP_NOIO, bs);
 
                if (idx != bio->bi_idx || clone->bi_size < bio->bi_size)
                        bio_integrity_trim(clone,
index 15c8b7b..5810fa9 100644 (file)
@@ -166,8 +166,8 @@ static linear_conf_t *linear_conf(mddev_t *mddev, int raid_disks)
                        rdev->sectors = sectors * mddev->chunk_sectors;
                }
 
-               blk_queue_stack_limits(mddev->queue,
-                                      rdev->bdev->bd_disk->queue);
+               disk_stack_limits(mddev->gendisk, rdev->bdev,
+                                 rdev->data_offset << 9);
                /* as we don't honour merge_bvec_fn, we must never risk
                 * violating it, so limit ->max_sector to one PAGE, as
                 * a one page request is never in violation.
index 09be637..0f4a70c 100644 (file)
@@ -3573,7 +3573,8 @@ suspend_lo_store(mddev_t *mddev, const char *buf, size_t len)
        char *e;
        unsigned long long new = simple_strtoull(buf, &e, 10);
 
-       if (mddev->pers->quiesce == NULL)
+       if (mddev->pers == NULL || 
+           mddev->pers->quiesce == NULL)
                return -EINVAL;
        if (buf == e || (*e && *e != '\n'))
                return -EINVAL;
@@ -3601,7 +3602,8 @@ suspend_hi_store(mddev_t *mddev, const char *buf, size_t len)
        char *e;
        unsigned long long new = simple_strtoull(buf, &e, 10);
 
-       if (mddev->pers->quiesce == NULL)
+       if (mddev->pers == NULL ||
+           mddev->pers->quiesce == NULL)
                return -EINVAL;
        if (buf == e || (*e && *e != '\n'))
                return -EINVAL;
@@ -3844,11 +3846,9 @@ static int md_alloc(dev_t dev, char *name)
        flush_scheduled_work();
 
        mutex_lock(&disks_mutex);
-       if (mddev->gendisk) {
-               mutex_unlock(&disks_mutex);
-               mddev_put(mddev);
-               return -EEXIST;
-       }
+       error = -EEXIST;
+       if (mddev->gendisk)
+               goto abort;
 
        if (name) {
                /* Need to ensure that 'name' is not a duplicate.
@@ -3860,17 +3860,15 @@ static int md_alloc(dev_t dev, char *name)
                        if (mddev2->gendisk &&
                            strcmp(mddev2->gendisk->disk_name, name) == 0) {
                                spin_unlock(&all_mddevs_lock);
-                               return -EEXIST;
+                               goto abort;
                        }
                spin_unlock(&all_mddevs_lock);
        }
 
+       error = -ENOMEM;
        mddev->queue = blk_alloc_queue(GFP_KERNEL);
-       if (!mddev->queue) {
-               mutex_unlock(&disks_mutex);
-               mddev_put(mddev);
-               return -ENOMEM;
-       }
+       if (!mddev->queue)
+               goto abort;
        mddev->queue->queuedata = mddev;
 
        /* Can be unlocked because the queue is new: no concurrency */
@@ -3880,11 +3878,9 @@ static int md_alloc(dev_t dev, char *name)
 
        disk = alloc_disk(1 << shift);
        if (!disk) {
-               mutex_unlock(&disks_mutex);
                blk_cleanup_queue(mddev->queue);
                mddev->queue = NULL;
-               mddev_put(mddev);
-               return -ENOMEM;
+               goto abort;
        }
        disk->major = MAJOR(mddev->unit);
        disk->first_minor = unit << shift;
@@ -3906,16 +3902,22 @@ static int md_alloc(dev_t dev, char *name)
        mddev->gendisk = disk;
        error = kobject_init_and_add(&mddev->kobj, &md_ktype,
                                     &disk_to_dev(disk)->kobj, "%s", "md");
-       mutex_unlock(&disks_mutex);
-       if (error)
+       if (error) {
+               /* This isn't possible, but as kobject_init_and_add is marked
+                * __must_check, we must do something with the result
+                */
                printk(KERN_WARNING "md: cannot register %s/md - name in use\n",
                       disk->disk_name);
-       else {
+               error = 0;
+       }
+ abort:
+       mutex_unlock(&disks_mutex);
+       if (!error) {
                kobject_uevent(&mddev->kobj, KOBJ_ADD);
                mddev->sysfs_state = sysfs_get_dirent(mddev->kobj.sd, "array_state");
        }
        mddev_put(mddev);
-       return 0;
+       return error;
 }
 
 static struct kobject *md_probe(dev_t dev, int *part, void *data)
@@ -6334,10 +6336,16 @@ void md_do_sync(mddev_t *mddev)
                        sysfs_notify(&mddev->kobj, NULL, "sync_completed");
                }
 
-               if (j >= mddev->resync_max)
-                       wait_event(mddev->recovery_wait,
-                                  mddev->resync_max > j
-                                  || kthread_should_stop());
+               while (j >= mddev->resync_max && !kthread_should_stop()) {
+                       /* As this condition is controlled by user-space,
+                        * we can block indefinitely, so use '_interruptible'
+                        * to avoid triggering warnings.
+                        */
+                       flush_signals(current); /* just in case */
+                       wait_event_interruptible(mddev->recovery_wait,
+                                                mddev->resync_max > j
+                                                || kthread_should_stop());
+               }
 
                if (kthread_should_stop())
                        goto interrupted;
index cbe368f..237fe3f 100644 (file)
@@ -294,7 +294,8 @@ static int multipath_add_disk(mddev_t *mddev, mdk_rdev_t *rdev)
        for (path = first; path <= last; path++)
                if ((p=conf->multipaths+path)->rdev == NULL) {
                        q = rdev->bdev->bd_disk->queue;
-                       blk_queue_stack_limits(mddev->queue, q);
+                       disk_stack_limits(mddev->gendisk, rdev->bdev,
+                                         rdev->data_offset << 9);
 
                /* as we don't honour merge_bvec_fn, we must never risk
                 * violating it, so limit ->max_sector to one PAGE, as
@@ -463,9 +464,9 @@ static int multipath_run (mddev_t *mddev)
 
                disk = conf->multipaths + disk_idx;
                disk->rdev = rdev;
+               disk_stack_limits(mddev->gendisk, rdev->bdev,
+                                 rdev->data_offset << 9);
 
-               blk_queue_stack_limits(mddev->queue,
-                                      rdev->bdev->bd_disk->queue);
                /* as we don't honour merge_bvec_fn, we must never risk
                 * violating it, not that we ever expect a device with
                 * a merge_bvec_fn to be involved in multipath */
index ab4a489..335f490 100644 (file)
@@ -170,8 +170,8 @@ static int create_strip_zones(mddev_t *mddev)
                }
                dev[j] = rdev1;
 
-               blk_queue_stack_limits(mddev->queue,
-                                      rdev1->bdev->bd_disk->queue);
+               disk_stack_limits(mddev->gendisk, rdev1->bdev,
+                                 rdev1->data_offset << 9);
                /* as we don't honour merge_bvec_fn, we must never risk
                 * violating it, so limit ->max_sector to one PAGE, as
                 * a one page request is never in violation.
@@ -250,6 +250,11 @@ static int create_strip_zones(mddev_t *mddev)
                       mddev->chunk_sectors << 9);
                goto abort;
        }
+
+       blk_queue_io_min(mddev->queue, mddev->chunk_sectors << 9);
+       blk_queue_io_opt(mddev->queue,
+                        (mddev->chunk_sectors << 9) * mddev->raid_disks);
+
        printk(KERN_INFO "raid0: done.\n");
        mddev->private = conf;
        return 0;
index 89939a7..0569efb 100644 (file)
@@ -1123,8 +1123,8 @@ static int raid1_add_disk(mddev_t *mddev, mdk_rdev_t *rdev)
        for (mirror = first; mirror <= last; mirror++)
                if ( !(p=conf->mirrors+mirror)->rdev) {
 
-                       blk_queue_stack_limits(mddev->queue,
-                                              rdev->bdev->bd_disk->queue);
+                       disk_stack_limits(mddev->gendisk, rdev->bdev,
+                                         rdev->data_offset << 9);
                        /* as we don't honour merge_bvec_fn, we must never risk
                         * violating it, so limit ->max_sector to one PAGE, as
                         * a one page request is never in violation.
@@ -1988,9 +1988,8 @@ static int run(mddev_t *mddev)
                disk = conf->mirrors + disk_idx;
 
                disk->rdev = rdev;
-
-               blk_queue_stack_limits(mddev->queue,
-                                      rdev->bdev->bd_disk->queue);
+               disk_stack_limits(mddev->gendisk, rdev->bdev,
+                                 rdev->data_offset << 9);
                /* as we don't honour merge_bvec_fn, we must never risk
                 * violating it, so limit ->max_sector to one PAGE, as
                 * a one page request is never in violation.
index ae12cea..7298a5e 100644 (file)
@@ -1151,8 +1151,8 @@ static int raid10_add_disk(mddev_t *mddev, mdk_rdev_t *rdev)
        for ( ; mirror <= last ; mirror++)
                if ( !(p=conf->mirrors+mirror)->rdev) {
 
-                       blk_queue_stack_limits(mddev->queue,
-                                              rdev->bdev->bd_disk->queue);
+                       disk_stack_limits(mddev->gendisk, rdev->bdev,
+                                         rdev->data_offset << 9);
                        /* as we don't honour merge_bvec_fn, we must never risk
                         * violating it, so limit ->max_sector to one PAGE, as
                         * a one page request is never in violation.
@@ -2044,7 +2044,7 @@ raid10_size(mddev_t *mddev, sector_t sectors, int raid_disks)
 static int run(mddev_t *mddev)
 {
        conf_t *conf;
-       int i, disk_idx;
+       int i, disk_idx, chunk_size;
        mirror_info_t *disk;
        mdk_rdev_t *rdev;
        int nc, fc, fo;
@@ -2130,6 +2130,14 @@ static int run(mddev_t *mddev)
        spin_lock_init(&conf->device_lock);
        mddev->queue->queue_lock = &conf->device_lock;
 
+       chunk_size = mddev->chunk_sectors << 9;
+       blk_queue_io_min(mddev->queue, chunk_size);
+       if (conf->raid_disks % conf->near_copies)
+               blk_queue_io_opt(mddev->queue, chunk_size * conf->raid_disks);
+       else
+               blk_queue_io_opt(mddev->queue, chunk_size *
+                                (conf->raid_disks / conf->near_copies));
+
        list_for_each_entry(rdev, &mddev->disks, same_set) {
                disk_idx = rdev->raid_disk;
                if (disk_idx >= mddev->raid_disks
@@ -2138,9 +2146,8 @@ static int run(mddev_t *mddev)
                disk = conf->mirrors + disk_idx;
 
                disk->rdev = rdev;
-
-               blk_queue_stack_limits(mddev->queue,
-                                      rdev->bdev->bd_disk->queue);
+               disk_stack_limits(mddev->gendisk, rdev->bdev,
+                                 rdev->data_offset << 9);
                /* as we don't honour merge_bvec_fn, we must never risk
                 * violating it, so limit ->max_sector to one PAGE, as
                 * a one page request is never in violation.
index f9f991e..3783553 100644 (file)
@@ -3699,13 +3699,21 @@ static int make_request(struct request_queue *q, struct bio * bi)
                                        goto retry;
                                }
                        }
-                       /* FIXME what if we get a false positive because these
-                        * are being updated.
-                        */
-                       if (logical_sector >= mddev->suspend_lo &&
+
+                       if (bio_data_dir(bi) == WRITE &&
+                           logical_sector >= mddev->suspend_lo &&
                            logical_sector < mddev->suspend_hi) {
                                release_stripe(sh);
-                               schedule();
+                               /* As the suspend_* range is controlled by
+                                * userspace, we want an interruptible
+                                * wait.
+                                */
+                               flush_signals(current);
+                               prepare_to_wait(&conf->wait_for_overlap,
+                                               &w, TASK_INTERRUPTIBLE);
+                               if (logical_sector >= mddev->suspend_lo &&
+                                   logical_sector < mddev->suspend_hi)
+                                       schedule();
                                goto retry;
                        }
 
@@ -4452,7 +4460,7 @@ static raid5_conf_t *setup_conf(mddev_t *mddev)
 static int run(mddev_t *mddev)
 {
        raid5_conf_t *conf;
-       int working_disks = 0;
+       int working_disks = 0, chunk_size;
        mdk_rdev_t *rdev;
 
        if (mddev->recovery_cp != MaxSector)
@@ -4607,6 +4615,14 @@ static int run(mddev_t *mddev)
        md_set_array_sectors(mddev, raid5_size(mddev, 0, 0));
 
        blk_queue_merge_bvec(mddev->queue, raid5_mergeable_bvec);
+       chunk_size = mddev->chunk_sectors << 9;
+       blk_queue_io_min(mddev->queue, chunk_size);
+       blk_queue_io_opt(mddev->queue, chunk_size *
+                        (conf->raid_disks - conf->max_degraded));
+
+       list_for_each_entry(rdev, &mddev->disks, same_set)
+               disk_stack_limits(mddev->gendisk, rdev->bdev,
+                                 rdev->data_offset << 9);
 
        return 0;
 abort:
index 8280f8d..8c9ae0a 100644 (file)
@@ -904,7 +904,7 @@ static int dvb_net_sec_callback(const u8 *buffer1, size_t buffer1_len,
 static int dvb_net_tx(struct sk_buff *skb, struct net_device *dev)
 {
        dev_kfree_skb(skb);
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 static u8 mask_normal[6]={0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
index a9e48e2..bc2ec21 100644 (file)
@@ -795,7 +795,7 @@ mpt_lan_sdu_send (struct sk_buff *skb, struct net_device *dev)
                        IOC_AND_NETDEV_NAMES_s_s(dev),
                        le32_to_cpu(pSimple->FlagsLength)));
 
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
index 671a7ef..c1de4af 100644 (file)
@@ -238,8 +238,10 @@ static irqreturn_t pcap_adc_irq(int irq, void *_pcap)
        mutex_lock(&pcap->adc_mutex);
        req = pcap->adc_queue[pcap->adc_head];
 
-       if (WARN(!req, KERN_WARNING "adc irq without pending request\n"))
+       if (WARN(!req, KERN_WARNING "adc irq without pending request\n")) {
+               mutex_unlock(&pcap->adc_mutex);
                return IRQ_HANDLED;
+       }
 
        /* read requested channels results */
        ezx_pcap_read(pcap, PCAP_REG_ADC, &tmp);
index 4c7b796..0cc5eef 100644 (file)
@@ -367,7 +367,8 @@ int sm501_unit_power(struct device *dev, unsigned int unit, unsigned int to)
                break;
 
        default:
-               return -1;
+               gate = -1;
+               goto already;
        }
 
        writel(mode, sm->regs + SM501_POWER_MODE_CONTROL);
index 8d1c60a..b681bf8 100644 (file)
@@ -436,7 +436,7 @@ xpnet_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
        if (skb->data[0] == 0x33) {
                dev_kfree_skb(skb);
-               return 0;       /* nothing needed to be done */
+               return NETDEV_TX_OK;    /* nothing needed to be done */
        }
 
        /*
@@ -503,7 +503,7 @@ xpnet_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
        dev->stats.tx_packets++;
        dev->stats.tx_bytes += skb->len;
 
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 /*
index 240608c..a461017 100644 (file)
@@ -1313,6 +1313,12 @@ static int mmc_spi_probe(struct spi_device *spi)
        struct mmc_spi_host     *host;
        int                     status;
 
+       /* We rely on full duplex transfers, mostly to reduce
+        * per-transfer overheads (by making fewer transfers).
+        */
+       if (spi->master->flags & SPI_MASTER_HALF_DUPLEX)
+               return -EINVAL;
+
        /* MMC and SD specs only seem to care that sampling is on the
         * rising edge ... meaning SPI modes 0 or 3.  So either SPI mode
         * should be legit.  We'll use mode 0 since the steady state is 0,
index 5011fa7..1479da6 100644 (file)
@@ -194,7 +194,7 @@ static struct mtd_partition * newpart(char *s,
        parts[this_part].name = extra_mem;
        extra_mem += name_len + 1;
 
-       dbg(("partition %d: name <%s>, offset %x, size %x, mask flags %x\n",
+       dbg(("partition %d: name <%s>, offset %llx, size %llx, mask flags %x\n",
             this_part,
             parts[this_part].name,
             parts[this_part].offset,
index 59c4612..ae5fe91 100644 (file)
@@ -54,7 +54,7 @@
 #define        SR_SRWD                 0x80    /* SR write protect */
 
 /* Define max times to check status register before we give up. */
-#define        MAX_READY_WAIT_JIFFIES  (10 * HZ)       /* eg. M25P128 specs 6s max sector erase */
+#define        MAX_READY_WAIT_JIFFIES  (40 * HZ)       /* M25P16 specs 40s max chip erase */
 #define        CMD_SIZE                4
 
 #ifdef CONFIG_M25PXX_USE_FAST_READ
index 73f0522..d8cf29c 100644 (file)
@@ -226,7 +226,7 @@ static u16 INFTL_findfreeblock(struct INFTLrecord *inftl, int desperate)
        if (!desperate && inftl->numfreeEUNs < 2) {
                DEBUG(MTD_DEBUG_LEVEL1, "INFTL: there are too few free "
                        "EUNs (%d)\n", inftl->numfreeEUNs);
-               return 0xffff;
+               return BLOCK_NIL;
        }
 
        /* Scan for a free block */
@@ -281,7 +281,8 @@ static u16 INFTL_foldchain(struct INFTLrecord *inftl, unsigned thisVUC, unsigned
        silly = MAX_LOOPS;
        while (thisEUN < inftl->nb_blocks) {
                for (block = 0; block < inftl->EraseSize/SECTORSIZE; block ++) {
-                       if ((BlockMap[block] != 0xffff) || BlockDeleted[block])
+                       if ((BlockMap[block] != BLOCK_NIL) ||
+                           BlockDeleted[block])
                                continue;
 
                        if (inftl_read_oob(mtd, (thisEUN * inftl->EraseSize)
@@ -525,7 +526,7 @@ static inline u16 INFTL_findwriteunit(struct INFTLrecord *inftl, unsigned block)
                        if (!silly--) {
                                printk(KERN_WARNING "INFTL: infinite loop in "
                                        "Virtual Unit Chain 0x%x\n", thisVUC);
-                               return 0xffff;
+                               return BLOCK_NIL;
                        }
 
                        /* Skip to next block in chain */
@@ -549,7 +550,7 @@ hitused:
                         * waiting to be picked up. We're going to have to fold
                         * a chain to make room.
                         */
-                       thisEUN = INFTL_makefreeblock(inftl, 0xffff);
+                       thisEUN = INFTL_makefreeblock(inftl, BLOCK_NIL);
 
                        /*
                         * Hopefully we free something, lets try again.
@@ -631,7 +632,7 @@ hitused:
 
        printk(KERN_WARNING "INFTL: error folding to make room for Virtual "
                "Unit Chain 0x%x\n", thisVUC);
-       return 0xffff;
+       return BLOCK_NIL;
 }
 
 /*
index b08a798..2aac41b 100644 (file)
 #include <mach/hardware.h>
 #include <asm/system.h>
 
-#define SUBDEV_NAME_SIZE       (BUS_ID_SIZE + 2)
-
 struct armflash_subdev_info {
-       char                    name[SUBDEV_NAME_SIZE];
+       char                    *name;
        struct mtd_info         *mtd;
        struct map_info         map;
        struct flash_platform_data *plat;
@@ -134,6 +132,8 @@ static void armflash_subdev_remove(struct armflash_subdev_info *subdev)
                map_destroy(subdev->mtd);
        if (subdev->map.virt)
                iounmap(subdev->map.virt);
+       kfree(subdev->name);
+       subdev->name = NULL;
        release_mem_region(subdev->map.phys, subdev->map.size);
 }
 
@@ -177,16 +177,22 @@ static int armflash_probe(struct platform_device *dev)
 
                if (nr == 1)
                        /* No MTD concatenation, just use the default name */
-                       snprintf(subdev->name, SUBDEV_NAME_SIZE, "%s",
-                                dev_name(&dev->dev));
+                       subdev->name = kstrdup(dev_name(&dev->dev), GFP_KERNEL);
                else
-                       snprintf(subdev->name, SUBDEV_NAME_SIZE, "%s-%d",
-                                dev_name(&dev->dev), i);
+                       subdev->name = kasprintf(GFP_KERNEL, "%s-%d",
+                                                dev_name(&dev->dev), i);
+               if (!subdev->name) {
+                       err = -ENOMEM;
+                       break;
+               }
                subdev->plat = plat;
 
                err = armflash_subdev_probe(subdev, res);
-               if (err)
+               if (err) {
+                       kfree(subdev->name);
+                       subdev->name = NULL;
                        break;
+               }
        }
        info->nr_subdev = i;
 
index 2802992..20c828b 100644 (file)
@@ -534,7 +534,7 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
                                                         &num_partitions);
 
        if ((!partitions) || (num_partitions == 0)) {
-               printk(KERN_ERR "atmel_nand: No parititions defined, or unsupported device.\n");
+               printk(KERN_ERR "atmel_nand: No partitions defined, or unsupported device.\n");
                res = ENXIO;
                goto err_no_partitions;
        }
index 0cd76f8..ebd07e9 100644 (file)
@@ -11,6 +11,8 @@
 #include <linux/platform_device.h>
 #include <linux/dma-mapping.h>
 #include <linux/delay.h>
+#include <linux/jiffies.h>
+#include <linux/sched.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/nand.h>
 #include <linux/mtd/partitions.h>
@@ -541,7 +543,7 @@ static int omap_wait(struct mtd_info *mtd, struct nand_chip *chip)
        struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
                                                        mtd);
        unsigned long timeo = jiffies;
-       int status, state = this->state;
+       int status = NAND_STATUS_FAIL, state = this->state;
 
        if (state == FL_ERASING)
                timeo += (HZ * 400) / 1000;
@@ -556,8 +558,9 @@ static int omap_wait(struct mtd_info *mtd, struct nand_chip *chip)
 
        while (time_before(jiffies, timeo)) {
                status = __raw_readb(this->IO_ADDR_R);
-               if (!(status & 0x40))
+               if (status & NAND_STATUS_READY)
                        break;
+               cond_resched();
        }
        return status;
 }
index e3f8495..fb86cac 100644 (file)
@@ -208,7 +208,7 @@ static u16 NFTL_findfreeblock(struct NFTLrecord *nftl, int desperate )
        /* Normally, we force a fold to happen before we run out of free blocks completely */
        if (!desperate && nftl->numfreeEUNs < 2) {
                DEBUG(MTD_DEBUG_LEVEL1, "NFTL_findfreeblock: there are too few free EUNs\n");
-               return 0xffff;
+               return BLOCK_NIL;
        }
 
        /* Scan for a free block */
@@ -230,11 +230,11 @@ static u16 NFTL_findfreeblock(struct NFTLrecord *nftl, int desperate )
                        printk("Argh! No free blocks found! LastFreeEUN = %d, "
                               "FirstEUN = %d\n", nftl->LastFreeEUN,
                               le16_to_cpu(nftl->MediaHdr.FirstPhysicalEUN));
-                       return 0xffff;
+                       return BLOCK_NIL;
                }
        } while (pot != nftl->LastFreeEUN);
 
-       return 0xffff;
+       return BLOCK_NIL;
 }
 
 static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned pendingblock )
@@ -431,7 +431,7 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p
 
        /* add the header so that it is now a valid chain */
        oob.u.a.VirtUnitNum = oob.u.a.SpareVirtUnitNum = cpu_to_le16(thisVUC);
-       oob.u.a.ReplUnitNum = oob.u.a.SpareReplUnitNum = 0xffff;
+       oob.u.a.ReplUnitNum = oob.u.a.SpareReplUnitNum = BLOCK_NIL;
 
        nftl_write_oob(mtd, (nftl->EraseSize * targetEUN) + 8,
                       8, &retlen, (char *)&oob.u);
@@ -515,7 +515,7 @@ static u16 NFTL_makefreeblock( struct NFTLrecord *nftl , unsigned pendingblock)
        if (ChainLength < 2) {
                printk(KERN_WARNING "No Virtual Unit Chains available for folding. "
                       "Failing request\n");
-               return 0xffff;
+               return BLOCK_NIL;
        }
 
        return NFTL_foldchain (nftl, LongestChain, pendingblock);
@@ -578,7 +578,7 @@ static inline u16 NFTL_findwriteunit(struct NFTLrecord *nftl, unsigned block)
                                printk(KERN_WARNING
                                       "Infinite loop in Virtual Unit Chain 0x%x\n",
                                       thisVUC);
-                               return 0xffff;
+                               return BLOCK_NIL;
                        }
 
                        /* Skip to next block in chain */
@@ -601,7 +601,7 @@ static inline u16 NFTL_findwriteunit(struct NFTLrecord *nftl, unsigned block)
                        //u16 startEUN = nftl->EUNtable[thisVUC];
 
                        //printk("Write to VirtualUnitChain %d, calling makefreeblock()\n", thisVUC);
-                       writeEUN = NFTL_makefreeblock(nftl, 0xffff);
+                       writeEUN = NFTL_makefreeblock(nftl, BLOCK_NIL);
 
                        if (writeEUN == BLOCK_NIL) {
                                /* OK, we accept that the above comment is
@@ -673,7 +673,7 @@ static inline u16 NFTL_findwriteunit(struct NFTLrecord *nftl, unsigned block)
 
        printk(KERN_WARNING "Error folding to make room for Virtual Unit Chain 0x%x\n",
               thisVUC);
-       return 0xffff;
+       return BLOCK_NIL;
 }
 
 static int nftl_writeblock(struct mtd_blktrans_dev *mbd, unsigned long block,
index 367bec6..e29fb1a 100644 (file)
@@ -485,7 +485,7 @@ static int el_start_xmit(struct sk_buff *skb, struct net_device *dev)
                        if (el_debug > 2)
                                pr_debug(" queued xmit.\n");
                        dev_kfree_skb(skb);
-                       return 0;
+                       return NETDEV_TX_OK;
                }
                /* A receive upset our load, despite our best efforts */
                if (el_debug > 2)
index f71b354..7bba480 100644 (file)
@@ -1101,7 +1101,7 @@ static int elp_start_xmit(struct sk_buff *skb, struct net_device *dev)
        prime_rx(dev);
        spin_unlock_irqrestore(&adapter->lock, flags);
        netif_start_queue(dev);
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 /******************************************************
index 96b8665..9e93a0b 100644 (file)
@@ -537,7 +537,7 @@ static int el16_send_packet (struct sk_buff *skb, struct net_device *dev)
 
        /* You might need to clean up and record Tx statistics here. */
 
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 /*     The typical workload of the driver:
index d2137ef..d2515d8 100644 (file)
@@ -892,7 +892,7 @@ el3_start_xmit(struct sk_buff *skb, struct net_device *dev)
                        outb(0x00, ioaddr + TX_STATUS); /* Pop the status stack. */
                }
        }
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 /* The EL3 interrupt handler. */
index 3e00fa8..85ffd13 100644 (file)
@@ -1054,7 +1054,7 @@ static int corkscrew_start_xmit(struct sk_buff *skb,
                        netif_wake_queue(dev);
                }
                dev->trans_start = jiffies;
-               return 0;
+               return NETDEV_TX_OK;
        }
        /* Put out the doubleword header... */
        outl(skb->len, ioaddr + TX_FIFO);
@@ -1117,7 +1117,7 @@ static int corkscrew_start_xmit(struct sk_buff *skb,
                        outb(0x00, ioaddr + TxStatus);  /* Pop the status stack. */
                }
        }
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 /* The interrupt handler does all of the Rx thread work and cleans up
index cdd955c..70c701b 100644 (file)
@@ -1198,7 +1198,7 @@ static int elmc_send_packet(struct sk_buff *skb, struct net_device *dev)
                netif_wake_queue(dev);
        dev_kfree_skb(skb);
 #endif
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 /*******************************************
index aaa8a9f..72b9ed7 100644 (file)
@@ -1035,7 +1035,7 @@ static int mc32_send_packet(struct sk_buff *skb, struct net_device *dev)
 
        if (skb_padto(skb, ETH_ZLEN)) {
                netif_wake_queue(dev);
-               return 0;
+               return NETDEV_TX_OK;
        }
 
        atomic_dec(&lp->tx_count);
@@ -1066,7 +1066,7 @@ static int mc32_send_packet(struct sk_buff *skb, struct net_device *dev)
        p->control     &= ~CONTROL_EOL;
 
        netif_wake_queue(dev);
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 
index c34aee9..2020484 100644 (file)
@@ -2083,7 +2083,7 @@ vortex_start_xmit(struct sk_buff *skb, struct net_device *dev)
                        iowrite8(0x00, ioaddr + TxStatus); /* Pop the status stack. */
                }
        }
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 static int
@@ -2173,7 +2173,7 @@ boomerang_start_xmit(struct sk_buff *skb, struct net_device *dev)
        iowrite16(DownUnstall, ioaddr + EL3_CMD);
        spin_unlock_irqrestore(&vp->lock, flags);
        dev->trans_start = jiffies;
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 /* The interrupt handler does all of the Rx thread work and cleans up
index 69f5b7d..b1e5764 100644 (file)
@@ -585,7 +585,7 @@ int lance_start_xmit (struct sk_buff *skb, struct net_device *dev)
                lp->tx_full = 1;
        spin_unlock_irqrestore (&lp->devlock, flags);
 
-        return 0;
+        return NETDEV_TX_OK;
 }
 EXPORT_SYMBOL_GPL(lance_start_xmit);
 
index 50efde1..07919d0 100644 (file)
@@ -891,7 +891,7 @@ static int cp_start_xmit (struct sk_buff *skb, struct net_device *dev)
        cpw8(TxPoll, NormalTxPoll);
        dev->trans_start = jiffies;
 
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 /* Set or clear the multicast filter for this adaptor.
index 0e2ba21..b39ec98 100644 (file)
@@ -1707,7 +1707,7 @@ static int rtl8139_start_xmit (struct sk_buff *skb, struct net_device *dev)
        } else {
                dev_kfree_skb(skb);
                dev->stats.tx_dropped++;
-               return 0;
+               return NETDEV_TX_OK;
        }
 
        spin_lock_irqsave(&tp->lock, flags);
@@ -1732,7 +1732,7 @@ static int rtl8139_start_xmit (struct sk_buff *skb, struct net_device *dev)
                pr_debug("%s: Queued Tx packet size %u to slot %d.\n",
                        dev->name, len, entry);
 
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 
index 7754754..996cc91 100644 (file)
@@ -1068,7 +1068,7 @@ static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
        if (skb->len < ETH_ZLEN) {
                if (skb_padto(skb, ETH_ZLEN))
-                       return 0;
+                       return NETDEV_TX_OK;
                length = ETH_ZLEN;
        }
        netif_stop_queue(dev);
@@ -1110,7 +1110,7 @@ static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
        netif_start_queue(dev);
 
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 static void print_eth(unsigned char *add, char *str)
index 85a1817..7302e43 100644 (file)
@@ -553,11 +553,11 @@ static int lance_start_xmit (struct sk_buff *skb, struct net_device *dev)
        volatile struct lance_regs *ll = lp->ll;
        volatile struct lance_init_block *ib = lp->init_block;
        int entry, skblen;
-       int status = 0;
+       int status = NETDEV_TX_OK;
        unsigned long flags;
 
        if (skb_padto(skb, ETH_ZLEN))
-               return 0;
+               return NETDEV_TX_OK;
        skblen = max_t(unsigned, skb->len, ETH_ZLEN);
 
        local_irq_save(flags);
index 19831bd..61ac671 100644 (file)
@@ -1346,7 +1346,7 @@ static int amd8111e_start_xmit(struct sk_buff *skb, struct net_device * dev)
                netif_stop_queue(dev);
        }
        spin_unlock_irqrestore(&lp->lock, flags);
-       return 0;
+       return NETDEV_TX_OK;
 }
 /*
 This function returns all the memory mapped registers of the device.
index 7f83254..29b279f 100644 (file)
@@ -920,7 +920,7 @@ static int cops_send_packet(struct sk_buff *skb, struct net_device *dev)
        dev->stats.tx_bytes += skb->len;
        dev->trans_start = jiffies;
        dev_kfree_skb (skb);
-        return 0;
+        return NETDEV_TX_OK;
 }
 
 /*
index 78cea5e..6cfd961 100644 (file)
@@ -132,7 +132,7 @@ static int ipddp_xmit(struct sk_buff *skb, struct net_device *dev)
         }
         if(rt == NULL) {
                spin_unlock(&ipddp_route_lock);
-                return 0;
+                return NETDEV_TX_OK;
        }
 
         our_addr = atalk_find_dev_addr(rt->dev);
@@ -181,7 +181,7 @@ static int ipddp_xmit(struct sk_buff *skb, struct net_device *dev)
 
        spin_unlock(&ipddp_route_lock);
 
-        return 0;
+        return NETDEV_TX_OK;
 }
 
 /*
index b642647..c80fb9c 100644 (file)
@@ -932,7 +932,7 @@ static int ltpc_xmit(struct sk_buff *skb, struct net_device *dev)
        dev->stats.tx_bytes += skb->len;
 
        dev_kfree_skb(skb);
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 /* initialization stuff */
index 58e8d52..47d976c 100644 (file)
@@ -610,7 +610,7 @@ static int ariadne_start_xmit(struct sk_buff *skb, struct net_device *dev)
     if (skb->len < ETH_ZLEN)
     {
        if (skb_padto(skb, ETH_ZLEN))
-           return 0;
+           return NETDEV_TX_OK;
        len = ETH_ZLEN;
     }
 
@@ -685,7 +685,7 @@ static int ariadne_start_xmit(struct sk_buff *skb, struct net_device *dev)
     }
     local_irq_restore(flags);
 
-    return 0;
+    return NETDEV_TX_OK;
 }
 
 
index 627bc75..164b37e 100644 (file)
@@ -482,7 +482,7 @@ am79c961_sendpacket(struct sk_buff *skb, struct net_device *dev)
 
        dev_kfree_skb(skb);
 
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 /*
index 5041d10..c8bc60a 100644 (file)
@@ -834,7 +834,7 @@ static int at91ether_start_xmit(struct sk_buff *skb, struct net_device *dev)
                                we free and return(0) or don't free and return 1 */
        }
 
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 /*
index edf770f..e47c0d9 100644 (file)
@@ -748,7 +748,7 @@ ether1_sendpacket (struct sk_buff *skb, struct net_device *dev)
                netif_stop_queue(dev);
 
  out:
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 static void
index 4550371..1f7a69c 100644 (file)
@@ -511,7 +511,7 @@ ether3_sendpacket(struct sk_buff *skb, struct net_device *dev)
                dev_kfree_skb(skb);
                priv(dev)->stats.tx_dropped ++;
                netif_start_queue(dev);
-               return 0;
+               return NETDEV_TX_OK;
        }
 
        length = (length + 1) & ~1;
@@ -562,7 +562,7 @@ ether3_sendpacket(struct sk_buff *skb, struct net_device *dev)
                netif_stop_queue(dev);
 
  out:
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 static irqreturn_t
index 18b566a..c2227d7 100644 (file)
@@ -643,7 +643,7 @@ static int net_send_packet (struct sk_buff *skb, struct net_device *dev)
                netif_start_queue (dev);
        dev_kfree_skb (skb);
 
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 /* The typical workload of the driver:
index 5425ab0..0c0dece 100644 (file)
@@ -796,7 +796,7 @@ static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev )
 
        if (len > skb->len) {
                if (skb_padto(skb, len))
-                       return 0;
+                       return NETDEV_TX_OK;
        }
 
        netif_stop_queue (dev);
@@ -846,7 +846,7 @@ static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev )
                lp->tx_full = 1;
        spin_unlock_irqrestore (&lp->devlock, flags);
 
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 /* The LANCE interrupt handler. */
index 4317b3e..4beacc9 100644 (file)
@@ -587,7 +587,7 @@ static int atp_send_packet(struct sk_buff *skb, struct net_device *dev)
 
        dev->trans_start = jiffies;
        dev_kfree_skb (skb);
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 
index d3c734f..2aab1eb 100644 (file)
@@ -988,7 +988,7 @@ static int au1000_tx(struct sk_buff *skb, struct net_device *dev)
        dev_kfree_skb(skb);
        aup->tx_head = (aup->tx_head + 1) & (NUM_TX_DMA - 1);
        dev->trans_start = jiffies;
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 /*
index 36d4d37..1f7f015 100644 (file)
@@ -1756,15 +1756,15 @@ static void b44_get_drvinfo (struct net_device *dev, struct ethtool_drvinfo *inf
        struct b44 *bp = netdev_priv(dev);
        struct ssb_bus *bus = bp->sdev->bus;
 
-       strncpy(info->driver, DRV_MODULE_NAME, sizeof(info->driver));
-       strncpy(info->version, DRV_MODULE_VERSION, sizeof(info->driver));
+       strlcpy(info->driver, DRV_MODULE_NAME, sizeof(info->driver));
+       strlcpy(info->version, DRV_MODULE_VERSION, sizeof(info->version));
        switch (bus->bustype) {
        case SSB_BUSTYPE_PCI:
-               strncpy(info->bus_info, pci_name(bus->host_pci), sizeof(info->bus_info));
+               strlcpy(info->bus_info, pci_name(bus->host_pci), sizeof(info->bus_info));
                break;
        case SSB_BUSTYPE_PCMCIA:
        case SSB_BUSTYPE_SSB:
-               strncpy(info->bus_info, "SSB", sizeof(info->bus_info));
+               strlcpy(info->bus_info, "SSB", sizeof(info->bus_info));
                break;
        }
 }
index c6934f1..fdb6e81 100644 (file)
@@ -1,7 +1,6 @@
 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.
index 5b4bf3d..41cddbe 100644 (file)
 #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_VER                        "2.0.400"
 #define DRV_NAME               "be2net"
 #define BE_NAME                        "ServerEngines BladeEngine2 10Gbps NIC"
 #define OC_NAME                        "Emulex OneConnect 10Gbps NIC"
@@ -72,9 +71,6 @@ static inline char *nic_name(struct pci_dev *pdev)
 #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  (min((u32) 16, (u32) MAX_SKB_FRAGS))
-
 struct be_dma_mem {
        void *va;
        dma_addr_t dma;
@@ -189,8 +185,6 @@ struct be_drvr_stats {
        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 */
        ulong be_rx_jiffies;
        u64 be_rx_bytes;
        u64 be_rx_bytes_prev;
@@ -233,8 +227,6 @@ 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 */
@@ -271,7 +263,6 @@ struct be_adapter {
 
        /* 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 */
index cccc541..f3f0f91 100644 (file)
@@ -127,8 +127,6 @@ be_get_coalesce(struct net_device *netdev, struct ethtool_coalesce *coalesce)
        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;
@@ -144,8 +142,7 @@ be_get_coalesce(struct net_device *netdev, struct ethtool_coalesce *coalesce)
 }
 
 /*
- * This routine is used to set interrup coalescing delay *as well as*
- * the number of pkts to coalesce for LRO.
+ * This routine is used to set interrup coalescing delay
  */
 static int
 be_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *coalesce)
@@ -161,10 +158,6 @@ be_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *coalesce)
        if (coalesce->use_adaptive_tx_coalesce == 1)
                return -EINVAL;
 
-       adapter->max_rx_coal = coalesce->rx_max_coalesced_frames;
-       if (adapter->max_rx_coal > BE_MAX_FRAGS_PER_FRAME)
-               adapter->max_rx_coal = BE_MAX_FRAGS_PER_FRAME;
-
        /* 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) {
index dea3155..c56487e 100644 (file)
@@ -742,7 +742,7 @@ done:
        return;
 }
 
-/* Process the RX completion indicated by rxcp when LRO is disabled */
+/* Process the RX completion indicated by rxcp when GRO is disabled */
 static void be_rx_compl_process(struct be_adapter *adapter,
                        struct be_eth_rx_compl *rxcp)
 {
@@ -789,13 +789,14 @@ static void be_rx_compl_process(struct be_adapter *adapter,
        return;
 }
 
-/* Process the RX completion indicated by rxcp when LRO is enabled */
-static void be_rx_compl_process_lro(struct be_adapter *adapter,
+/* Process the RX completion indicated by rxcp when GRO is enabled */
+static void be_rx_compl_process_gro(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 sk_buff *skb = NULL;
        struct be_queue_info *rxq = &adapter->rx_obj.q;
+       struct be_eq_obj *eq_obj =  &adapter->rx_eq;
        u32 num_rcvd, pkt_size, remaining, vlanf, curr_frag_len;
        u16 i, rxq_idx = 0, vid, j;
 
@@ -804,6 +805,12 @@ static void be_rx_compl_process_lro(struct be_adapter *adapter,
        vlanf = AMAP_GET_BITS(struct amap_eth_rx_compl, vtp, rxcp);
        rxq_idx = AMAP_GET_BITS(struct amap_eth_rx_compl, fragndx, rxcp);
 
+       skb = napi_get_frags(&eq_obj->napi);
+       if (!skb) {
+               be_rx_compl_discard(adapter, rxcp);
+               return;
+       }
+
        remaining = pkt_size;
        for (i = 0, j = -1; i < num_rcvd; i++) {
                page_info = get_rx_page_info(adapter, rxq_idx);
@@ -814,13 +821,14 @@ static void be_rx_compl_process_lro(struct be_adapter *adapter,
                if (i == 0 || page_info->page_offset == 0) {
                        /* First frag or Fresh page */
                        j++;
-                       rx_frags[j].page = page_info->page;
-                       rx_frags[j].page_offset = page_info->page_offset;
-                       rx_frags[j].size = 0;
+                       skb_shinfo(skb)->frags[j].page = page_info->page;
+                       skb_shinfo(skb)->frags[j].page_offset =
+                                                       page_info->page_offset;
+                       skb_shinfo(skb)->frags[j].size = 0;
                } else {
                        put_page(page_info->page);
                }
-               rx_frags[j].size += curr_frag_len;
+               skb_shinfo(skb)->frags[j].size += curr_frag_len;
 
                remaining -= curr_frag_len;
                index_inc(&rxq_idx, rxq->len);
@@ -828,9 +836,14 @@ static void be_rx_compl_process_lro(struct be_adapter *adapter,
        }
        BUG_ON(j > MAX_SKB_FRAGS);
 
+       skb_shinfo(skb)->nr_frags = j + 1;
+       skb->len = pkt_size;
+       skb->data_len = pkt_size;
+       skb->truesize += pkt_size;
+       skb->ip_summed = CHECKSUM_UNNECESSARY;
+
        if (likely(!vlanf)) {
-               lro_receive_frags(&adapter->rx_obj.lro_mgr, rx_frags, pkt_size,
-                               pkt_size, NULL, 0);
+               napi_gro_frags(&eq_obj->napi);
        } else {
                vid = AMAP_GET_BITS(struct amap_eth_rx_compl, vlan_tag, rxcp);
                vid = be16_to_cpu(vid);
@@ -838,9 +851,7 @@ static void be_rx_compl_process_lro(struct be_adapter *adapter,
                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);
+               vlan_gro_frags(&eq_obj->napi, adapter->vlan_grp, vid);
        }
 
        be_rx_stats_update(adapter, pkt_size, num_rcvd);
@@ -1183,7 +1194,6 @@ 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;
@@ -1305,7 +1315,7 @@ static irqreturn_t be_msix_tx_mcc(int irq, void *dev)
        return IRQ_HANDLED;
 }
 
-static inline bool do_lro(struct be_adapter *adapter,
+static inline bool do_gro(struct be_adapter *adapter,
                        struct be_eth_rx_compl *rxcp)
 {
        int err = AMAP_GET_BITS(struct amap_eth_rx_compl, err, rxcp);
@@ -1314,8 +1324,7 @@ static inline bool do_lro(struct be_adapter *adapter,
        if (err)
                drvr_stats(adapter)->be_rxcp_err++;
 
-       return (!tcp_frame || err || (adapter->max_rx_coal <= 1)) ?
-               false : true;
+       return (tcp_frame && !err) ? true : false;
 }
 
 int be_poll_rx(struct napi_struct *napi, int budget)
@@ -1332,16 +1341,14 @@ int be_poll_rx(struct napi_struct *napi, int budget)
                if (!rxcp)
                        break;
 
-               if (do_lro(adapter, rxcp))
-                       be_rx_compl_process_lro(adapter, rxcp);
+               if (do_gro(adapter, rxcp))
+                       be_rx_compl_process_gro(adapter, rxcp);
                else
                        be_rx_compl_process(adapter, rxcp);
 
                be_rx_compl_reset(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);
@@ -1656,57 +1663,6 @@ static int be_close(struct net_device *netdev)
        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,
@@ -1727,7 +1683,7 @@ static void be_netdev_init(struct net_device *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_IPV6_CSUM | NETIF_F_GRO;
 
        netdev->flags |= IFF_MULTICAST;
 
@@ -1737,8 +1693,6 @@ static void be_netdev_init(struct net_device *netdev)
 
        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_mcc,
index c15fc28..f580b21 100644 (file)
@@ -656,7 +656,7 @@ out:
        dev->trans_start = jiffies;
        dev->stats.tx_packets++;
        dev->stats.tx_bytes += (skb->len);
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 static void bfin_mac_rx(struct net_device *dev)
index 9578a3d..4160001 100644 (file)
@@ -1488,7 +1488,7 @@ bmac_output(struct sk_buff *skb, struct net_device *dev)
        struct bmac_data *bp = netdev_priv(dev);
        skb_queue_tail(bp->queue, skb);
        bmac_start(dev);
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 static void bmac_tx_timeout(unsigned long data)
index 85a737c..8bd80fc 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((typeof(PAGE_SIZE))addr)
+#define SGE_PAGE_ALIGN(addr)           PAGE_ALIGN((typeof(PAGE_SIZE))(addr))
 
 /* SGE ring related macros */
 #define NUM_RX_SGE_PAGES               2
@@ -1006,6 +1006,7 @@ void bnx2x_write_dmae(struct bnx2x *bp, dma_addr_t dma_addr, u32 dst_addr,
 int bnx2x_get_gpio(struct bnx2x *bp, int gpio_num, u8 port);
 int bnx2x_set_gpio(struct bnx2x *bp, int gpio_num, u32 mode, u8 port);
 int bnx2x_set_gpio_int(struct bnx2x *bp, int gpio_num, u32 mode, u8 port);
+u32 bnx2x_fw_command(struct bnx2x *bp, u32 command);
 
 static inline u32 reg_poll(struct bnx2x *bp, u32 reg, u32 expected, int ms,
                           int wait)
index 03c6242..7de83c4 100644 (file)
@@ -91,6 +91,21 @@ struct shared_hw_cfg {                                        /* NVRAM Offset */
 
 #define SHARED_HW_CFG_HIDE_PORT1                   0x00002000
 
+       /*  The fan failure mechanism is usually related to the PHY type
+         since the power consumption of the board is determined by the PHY.
+         Currently, fan is required for most designs with SFX7101, BCM8727
+         and BCM8481. If a fan is not required for a board which uses one
+         of those PHYs, this field should be set to "Disabled". If a fan is
+         required for a different PHY type, this option should be set to
+         "Enabled".
+         The fan failure indication is expected on
+         SPIO5 */
+#define SHARED_HW_CFG_FAN_FAILURE_MASK                       0x00180000
+#define SHARED_HW_CFG_FAN_FAILURE_SHIFT                      19
+#define SHARED_HW_CFG_FAN_FAILURE_PHY_TYPE                   0x00000000
+#define SHARED_HW_CFG_FAN_FAILURE_DISABLED                   0x00080000
+#define SHARED_HW_CFG_FAN_FAILURE_ENABLED                    0x00100000
+
        u32 power_dissipated;                                   /* 0x11c */
 #define SHARED_HW_CFG_POWER_DIS_CMN_MASK           0xff000000
 #define SHARED_HW_CFG_POWER_DIS_CMN_SHIFT          24
@@ -233,6 +248,8 @@ struct port_hw_cfg {                            /* port 0: 0x12c  port 1: 0x2bc */
 #define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726      0x00000600
 #define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481      0x00000700
 #define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101      0x00000800
+#define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727      0x00000900
+#define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727_NOC   0x00000a00
 #define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE      0x0000fd00
 #define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN     0x0000ff00
 
@@ -343,10 +360,16 @@ struct port_feat_cfg {                        /* port 0: 0x454  port 1: 0x4c8 */
 #define PORT_FEATURE_MBA_ENABLED                   0x02000000
 #define PORT_FEATURE_MFW_ENABLED                   0x04000000
 
-       /*  Check the optic vendor via i2c before allowing it to be used by
-         SW */
-#define PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLED              0x00000000
-#define PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_ENABLED               0x08000000
+       /* Reserved bits: 28-29 */
+       /*  Check the optic vendor via i2c against a list of approved modules
+         in a separate nvram image */
+#define PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK                  0xE0000000
+#define PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_SHIFT                 29
+#define PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_NO_ENFORCEMENT        0x00000000
+#define PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER       0x20000000
+#define PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_WARNING_MSG           0x40000000
+#define PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_POWER_DOWN            0x60000000
+
 
        u32 wol_config;
        /* Default is used when driver sets to "auto" mode */
@@ -642,6 +665,12 @@ struct drv_func_mb {
 #define DRV_MSG_CODE_GET_UPGRADE_KEY                   0x81000000
 #define DRV_MSG_CODE_GET_MANUF_KEY                     0x82000000
 #define DRV_MSG_CODE_LOAD_L2B_PRAM                     0x90000000
+       /*
+        * The optic module verification commands requris bootcode
+        * v5.0.6 or later
+        */
+#define DRV_MSG_CODE_VRFY_OPT_MDL                      0xa0000000
+#define REQ_BC_VER_4_VRFY_OPT_MDL                      0x00050006
 
 #define BIOS_MSG_CODE_LIC_CHALLENGE                    0xff010000
 #define BIOS_MSG_CODE_LIC_RESPONSE                     0xff020000
@@ -676,6 +705,9 @@ struct drv_func_mb {
 #define FW_MSG_CODE_L2B_PRAM_C_LOAD_FAILURE            0x90220000
 #define FW_MSG_CODE_L2B_PRAM_X_LOAD_FAILURE            0x90230000
 #define FW_MSG_CODE_L2B_PRAM_U_LOAD_FAILURE            0x90240000
+#define FW_MSG_CODE_VRFY_OPT_MDL_SUCCESS               0xa0100000
+#define FW_MSG_CODE_VRFY_OPT_MDL_INVLD_IMG             0xa0200000
+#define FW_MSG_CODE_VRFY_OPT_MDL_UNAPPROVED            0xa0300000
 
 #define FW_MSG_CODE_LIC_CHALLENGE                      0xff010000
 #define FW_MSG_CODE_LIC_RESPONSE                       0xff020000
index 2ee581a..1f17334 100644 (file)
        #define SFP_EEPROM_CON_TYPE_VAL_LC              0x7
        #define SFP_EEPROM_CON_TYPE_VAL_COPPER  0x21
 
+
+#define SFP_EEPROM_COMP_CODE_ADDR              0x3
+       #define SFP_EEPROM_COMP_CODE_SR_MASK    (1<<4)
+       #define SFP_EEPROM_COMP_CODE_LR_MASK    (1<<5)
+       #define SFP_EEPROM_COMP_CODE_LRM_MASK   (1<<6)
+
 #define SFP_EEPROM_FC_TX_TECH_ADDR             0x8
        #define SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_PASSIVE 0x4
        #define SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_ACTIVE      0x8
-#define SFP_EEPROM_VENDOR_NAME_ADDR            0x14
-#define SFP_EEPROM_VENDOR_NAME_SIZE    16
+
 #define SFP_EEPROM_OPTIONS_ADDR                0x40
        #define SFP_EEPROM_OPTIONS_LINEAR_RX_OUT_MASK 0x1
 #define SFP_EEPROM_OPTIONS_SIZE                2
 
-#define SFP_MODULE_TYPE_UNKNOWN                        0x0
-#define SFP_MODULE_TYPE_LC                     0x1
-#define SFP_MODULE_TYPE_ACTIVE_COPPER_CABLE            0x2
-#define SFP_MODULE_TYPE_PASSIVE_COPPER_CABLE   0x3
+#define EDC_MODE_LINEAR                                0x0022
+#define EDC_MODE_LIMITING                              0x0044
+#define EDC_MODE_PASSIVE_DAC                   0x0055
+
+
 
-#define SFP_LIMITING_MODE_VALUE                        0x0044
 /**********************************************************/
 /*                     INTERFACE                          */
 /**********************************************************/
@@ -793,6 +798,7 @@ static u32 bnx2x_get_emac_base(struct bnx2x *bp, u32 ext_phy_type, u8 port)
        switch (ext_phy_type) {
        case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
        case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
+       case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
                /* All MDC/MDIO is directed through single EMAC */
                if (REG_RD(bp, NIG_REG_PORT_SWAP))
                        emac_base = GRCBASE_EMAC0;
@@ -1887,6 +1893,10 @@ static void bnx2x_ext_phy_reset(struct link_params *params,
                                       MDIO_PMA_DEVAD,
                                       MDIO_PMA_REG_CTRL, 0xa040);
                        break;
+
+               case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
+                       break;
+
                case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
 
                        /* Restore normal power mode*/
@@ -2171,13 +2181,15 @@ static u8 bnx2x_bcm8073_xaui_wa(struct link_params *params)
 
 }
 
-static void bnx2x_bcm8073_external_rom_boot(struct bnx2x *bp, u8 port,
-                                         u8 ext_phy_addr, u32 shmem_base)
+static void bnx2x_bcm8073_bcm8727_external_rom_boot(struct bnx2x *bp, u8 port,
+                                                 u8 ext_phy_addr,
+                                                 u32 ext_phy_type,
+                                                 u32 shmem_base)
 {
        /* Boot port from external ROM  */
        /* EDC grst */
        bnx2x_cl45_write(bp, port,
-                      PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
+                      ext_phy_type,
                       ext_phy_addr,
                       MDIO_PMA_DEVAD,
                       MDIO_PMA_REG_GEN_CTRL,
@@ -2185,21 +2197,21 @@ static void bnx2x_bcm8073_external_rom_boot(struct bnx2x *bp, u8 port,
 
        /* ucode reboot and rst */
        bnx2x_cl45_write(bp, port,
-                      PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
+                      ext_phy_type,
                       ext_phy_addr,
                       MDIO_PMA_DEVAD,
                       MDIO_PMA_REG_GEN_CTRL,
                       0x008c);
 
        bnx2x_cl45_write(bp, port,
-                      PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
+                      ext_phy_type,
                       ext_phy_addr,
                       MDIO_PMA_DEVAD,
                       MDIO_PMA_REG_MISC_CTRL1, 0x0001);
 
        /* Reset internal microprocessor */
        bnx2x_cl45_write(bp, port,
-                      PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
+                      ext_phy_type,
                       ext_phy_addr,
                       MDIO_PMA_DEVAD,
                       MDIO_PMA_REG_GEN_CTRL,
@@ -2207,7 +2219,7 @@ static void bnx2x_bcm8073_external_rom_boot(struct bnx2x *bp, u8 port,
 
        /* Release srst bit */
        bnx2x_cl45_write(bp, port,
-                      PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
+                      ext_phy_type,
                       ext_phy_addr,
                       MDIO_PMA_DEVAD,
                       MDIO_PMA_REG_GEN_CTRL,
@@ -2218,17 +2230,36 @@ static void bnx2x_bcm8073_external_rom_boot(struct bnx2x *bp, u8 port,
 
        /* Clear ser_boot_ctl bit */
        bnx2x_cl45_write(bp, port,
-                      PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
+                      ext_phy_type,
                       ext_phy_addr,
                       MDIO_PMA_DEVAD,
                       MDIO_PMA_REG_MISC_CTRL1, 0x0000);
 
        bnx2x_save_bcm_spirom_ver(bp, port,
-                               PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
+                               ext_phy_type,
                                ext_phy_addr,
                                shmem_base);
 }
 
+static void bnx2x_bcm8073_external_rom_boot(struct bnx2x *bp, u8 port,
+                                         u8 ext_phy_addr,
+                                         u32 shmem_base)
+{
+       bnx2x_bcm8073_bcm8727_external_rom_boot(bp, port, ext_phy_addr,
+                                        PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
+                                        shmem_base);
+}
+
+static void bnx2x_bcm8727_external_rom_boot(struct bnx2x *bp, u8 port,
+                                         u8 ext_phy_addr,
+                                         u32 shmem_base)
+{
+       bnx2x_bcm8073_bcm8727_external_rom_boot(bp, port, ext_phy_addr,
+                                        PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
+                                        shmem_base);
+
+}
+
 static void bnx2x_bcm8726_external_rom_boot(struct link_params *params)
 {
        struct bnx2x *bp = params->bp;
@@ -2258,9 +2289,10 @@ static void bnx2x_bcm8726_external_rom_boot(struct link_params *params)
                       MDIO_PMA_REG_GEN_CTRL,
                       MDIO_PMA_REG_GEN_CTRL_ROM_MICRO_RESET);
 
+       /* Set PLL register value to be same like in P13 ver */
        bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
                       MDIO_PMA_DEVAD,
-                      MDIO_PMA_REG_GEN_CTRL2,
+                      MDIO_PMA_REG_PLL_CTRL,
                       0x73A0);
 
        /* Clear soft reset.
@@ -2285,15 +2317,16 @@ static void bnx2x_bcm8726_external_rom_boot(struct link_params *params)
                                params->shmem_base);
 }
 
-static void bnx2x_bcm8726_set_transmitter(struct bnx2x *bp, u8 port,
-                                       u8 ext_phy_addr, u8 tx_en)
+static void bnx2x_sfp_set_transmitter(struct bnx2x *bp, u8 port,
+                                   u32 ext_phy_type, u8 ext_phy_addr,
+                                   u8 tx_en)
 {
        u16 val;
        DP(NETIF_MSG_LINK, "Setting transmitter tx_en=%x for port %x\n",
                 tx_en, port);
        /* Disable/Enable transmitter ( TX laser of the SFP+ module.)*/
        bnx2x_cl45_read(bp, port,
-                     PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
+                     ext_phy_type,
                      ext_phy_addr,
                      MDIO_PMA_DEVAD,
                      MDIO_PMA_REG_PHY_IDENTIFIER,
@@ -2305,18 +2338,19 @@ static void bnx2x_bcm8726_set_transmitter(struct bnx2x *bp, u8 port,
                val |= (1<<15);
 
        bnx2x_cl45_write(bp, port,
-                      PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
+                      ext_phy_type,
                       ext_phy_addr,
                       MDIO_PMA_DEVAD,
                       MDIO_PMA_REG_PHY_IDENTIFIER,
                       val);
 }
 
-
-static u8 bnx2x_read_sfp_module_eeprom(struct link_params *params, u16 addr,
-                                    u8 byte_cnt, u8 *o_buf) {
+static u8 bnx2x_8726_read_sfp_module_eeprom(struct link_params *params,
+                                         u16 addr, u8 byte_cnt, u8 *o_buf)
+{
        struct bnx2x *bp = params->bp;
-       u16 val, i;
+       u16 val = 0;
+       u16 i;
        u8 port = params->port;
        u8 ext_phy_addr = ((params->ext_phy_config &
                            PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
@@ -2332,7 +2366,7 @@ static u8 bnx2x_read_sfp_module_eeprom(struct link_params *params, u16 addr,
                       ext_phy_type,
                       ext_phy_addr,
                       MDIO_PMA_DEVAD,
-                      MDIO_PMA_REG_8726_TWO_WIRE_BYTE_CNT,
+                      MDIO_PMA_REG_SFP_TWO_WIRE_BYTE_CNT,
                       (byte_cnt | 0xa000));
 
        /* Set the read command address */
@@ -2340,7 +2374,7 @@ static u8 bnx2x_read_sfp_module_eeprom(struct link_params *params, u16 addr,
                       ext_phy_type,
                       ext_phy_addr,
                       MDIO_PMA_DEVAD,
-                      MDIO_PMA_REG_8726_TWO_WIRE_MEM_ADDR,
+                      MDIO_PMA_REG_SFP_TWO_WIRE_MEM_ADDR,
                       addr);
 
        /* Activate read command */
@@ -2348,7 +2382,7 @@ static u8 bnx2x_read_sfp_module_eeprom(struct link_params *params, u16 addr,
                       ext_phy_type,
                       ext_phy_addr,
                       MDIO_PMA_DEVAD,
-                      MDIO_PMA_REG_8726_TWO_WIRE_CTRL,
+                      MDIO_PMA_REG_SFP_TWO_WIRE_CTRL,
                       0x2c0f);
 
        /* Wait up to 500us for command complete status */
@@ -2357,18 +2391,18 @@ static u8 bnx2x_read_sfp_module_eeprom(struct link_params *params, u16 addr,
                              ext_phy_type,
                              ext_phy_addr,
                              MDIO_PMA_DEVAD,
-                             MDIO_PMA_REG_8726_TWO_WIRE_CTRL, &val);
-               if ((val & MDIO_PMA_REG_8726_TWO_WIRE_CTRL_STATUS_MASK) ==
-                   MDIO_PMA_REG_8726_TWO_WIRE_STATUS_COMPLETE)
+                             MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val);
+               if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) ==
+                   MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE)
                        break;
                udelay(5);
        }
 
-       if ((val & MDIO_PMA_REG_8726_TWO_WIRE_CTRL_STATUS_MASK) !=
-                   MDIO_PMA_REG_8726_TWO_WIRE_STATUS_COMPLETE) {
+       if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) !=
+                   MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE) {
                DP(NETIF_MSG_LINK,
                         "Got bad status 0x%x when reading from SFP+ EEPROM\n",
-                        (val & MDIO_PMA_REG_8726_TWO_WIRE_CTRL_STATUS_MASK));
+                        (val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK));
                return -EINVAL;
        }
 
@@ -2387,29 +2421,147 @@ static u8 bnx2x_read_sfp_module_eeprom(struct link_params *params, u16 addr,
                              ext_phy_type,
                              ext_phy_addr,
                              MDIO_PMA_DEVAD,
-                             MDIO_PMA_REG_8726_TWO_WIRE_CTRL, &val);
-               if ((val & MDIO_PMA_REG_8726_TWO_WIRE_CTRL_STATUS_MASK) ==
-                   MDIO_PMA_REG_8726_TWO_WIRE_STATUS_IDLE)
+                             MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val);
+               if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) ==
+                   MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_IDLE)
+                       return 0;;
+               msleep(1);
+       }
+       return -EINVAL;
+}
+
+static u8 bnx2x_8727_read_sfp_module_eeprom(struct link_params *params,
+                                         u16 addr, u8 byte_cnt, u8 *o_buf)
+{
+       struct bnx2x *bp = params->bp;
+       u16 val, i;
+       u8 port = params->port;
+       u8 ext_phy_addr = ((params->ext_phy_config &
+                           PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
+                          PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
+       u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
+
+       if (byte_cnt > 16) {
+               DP(NETIF_MSG_LINK, "Reading from eeprom is"
+                           " is limited to 0xf\n");
+               return -EINVAL;
+       }
+
+       /* Need to read from 1.8000 to clear it */
+       bnx2x_cl45_read(bp, port,
+                     PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
+                     ext_phy_addr,
+                     MDIO_PMA_DEVAD,
+                     MDIO_PMA_REG_SFP_TWO_WIRE_CTRL,
+                     &val);
+
+       /* Set the read command byte count */
+       bnx2x_cl45_write(bp, port,
+                      ext_phy_type,
+                      ext_phy_addr,
+                      MDIO_PMA_DEVAD,
+                      MDIO_PMA_REG_SFP_TWO_WIRE_BYTE_CNT,
+                      ((byte_cnt < 2) ? 2 : byte_cnt));
+
+       /* Set the read command address */
+       bnx2x_cl45_write(bp, port,
+                      ext_phy_type,
+                      ext_phy_addr,
+                      MDIO_PMA_DEVAD,
+                      MDIO_PMA_REG_SFP_TWO_WIRE_MEM_ADDR,
+                      addr);
+       /* Set the destination address */
+       bnx2x_cl45_write(bp, port,
+                      ext_phy_type,
+                      ext_phy_addr,
+                      MDIO_PMA_DEVAD,
+                      0x8004,
+                      MDIO_PMA_REG_8727_TWO_WIRE_DATA_BUF);
+
+       /* Activate read command */
+       bnx2x_cl45_write(bp, port,
+                      ext_phy_type,
+                      ext_phy_addr,
+                      MDIO_PMA_DEVAD,
+                      MDIO_PMA_REG_SFP_TWO_WIRE_CTRL,
+                      0x8002);
+       /* Wait appropriate time for two-wire command to finish before
+       polling the status register */
+       msleep(1);
+
+       /* Wait up to 500us for command complete status */
+       for (i = 0; i < 100; i++) {
+               bnx2x_cl45_read(bp, port,
+                             ext_phy_type,
+                             ext_phy_addr,
+                             MDIO_PMA_DEVAD,
+                             MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val);
+               if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) ==
+                   MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE)
+                       break;
+               udelay(5);
+       }
+
+       if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) !=
+                   MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE) {
+               DP(NETIF_MSG_LINK,
+                        "Got bad status 0x%x when reading from SFP+ EEPROM\n",
+                        (val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK));
+               return -EINVAL;
+       }
+
+       /* Read the buffer */
+       for (i = 0; i < byte_cnt; i++) {
+               bnx2x_cl45_read(bp, port,
+                             ext_phy_type,
+                             ext_phy_addr,
+                             MDIO_PMA_DEVAD,
+                             MDIO_PMA_REG_8727_TWO_WIRE_DATA_BUF + i, &val);
+               o_buf[i] = (u8)(val & MDIO_PMA_REG_8727_TWO_WIRE_DATA_MASK);
+       }
+
+       for (i = 0; i < 100; i++) {
+               bnx2x_cl45_read(bp, port,
+                             ext_phy_type,
+                             ext_phy_addr,
+                             MDIO_PMA_DEVAD,
+                             MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val);
+               if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) ==
+                   MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_IDLE)
                        return 0;;
                msleep(1);
        }
+
        return -EINVAL;
 }
 
+u8 bnx2x_read_sfp_module_eeprom(struct link_params *params, u16 addr,
+                                    u8 byte_cnt, u8 *o_buf)
+{
+       u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
+
+       if (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726)
+               return bnx2x_8726_read_sfp_module_eeprom(params, addr,
+                                                      byte_cnt, o_buf);
+       else if (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727)
+               return bnx2x_8727_read_sfp_module_eeprom(params, addr,
+                                                      byte_cnt, o_buf);
+       return -EINVAL;
+}
 
-static u8 bnx2x_get_sfp_module_type(struct link_params *params,
-                                 u8 *module_type)
+static u8 bnx2x_get_edc_mode(struct link_params *params,
+                                 u16 *edc_mode)
 {
        struct bnx2x *bp = params->bp;
-       u8 val;
-       *module_type = SFP_MODULE_TYPE_UNKNOWN;
+       u8 val, check_limiting_mode = 0;
+       *edc_mode = EDC_MODE_LIMITING;
 
        /* First check for copper cable */
        if (bnx2x_read_sfp_module_eeprom(params,
                                       SFP_EEPROM_CON_TYPE_ADDR,
                                       1,
                                       &val) != 0) {
-               DP(NETIF_MSG_LINK, "Failed to read from SFP+ module EEPROM");
+               DP(NETIF_MSG_LINK, "Failed to read from SFP+ module EEPROM\n");
                return -EINVAL;
        }
 
@@ -2433,13 +2585,13 @@ static u8 bnx2x_get_sfp_module_type(struct link_params *params,
                if (copper_module_type &
                    SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_ACTIVE) {
                        DP(NETIF_MSG_LINK, "Active Copper cable detected\n");
-                       *module_type = SFP_MODULE_TYPE_ACTIVE_COPPER_CABLE;
+                       check_limiting_mode = 1;
                } else if (copper_module_type &
                        SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_PASSIVE) {
                                DP(NETIF_MSG_LINK, "Passive Copper"
                                            " cable detected\n");
-                               *module_type =
-                                     SFP_MODULE_TYPE_PASSIVE_COPPER_CABLE;
+                               *edc_mode =
+                                     EDC_MODE_PASSIVE_DAC;
                } else {
                        DP(NETIF_MSG_LINK, "Unknown copper-cable-"
                                     "type 0x%x !!!\n", copper_module_type);
@@ -2449,7 +2601,7 @@ static u8 bnx2x_get_sfp_module_type(struct link_params *params,
        }
        case SFP_EEPROM_CON_TYPE_VAL_LC:
                DP(NETIF_MSG_LINK, "Optic module detected\n");
-               *module_type = SFP_MODULE_TYPE_LC;
+               check_limiting_mode = 1;
                break;
 
        default:
@@ -2457,89 +2609,92 @@ static u8 bnx2x_get_sfp_module_type(struct link_params *params,
                         val);
                return -EINVAL;
        }
+
+       if (check_limiting_mode) {
+               u8 options[SFP_EEPROM_OPTIONS_SIZE];
+               if (bnx2x_read_sfp_module_eeprom(params,
+                                              SFP_EEPROM_OPTIONS_ADDR,
+                                              SFP_EEPROM_OPTIONS_SIZE,
+                                              options) != 0) {
+                       DP(NETIF_MSG_LINK, "Failed to read Option"
+                               " field from module EEPROM\n");
+                       return -EINVAL;
+               }
+               if ((options[0] & SFP_EEPROM_OPTIONS_LINEAR_RX_OUT_MASK))
+                       *edc_mode = EDC_MODE_LINEAR;
+               else
+                       *edc_mode = EDC_MODE_LIMITING;
+       }
+       DP(NETIF_MSG_LINK, "EDC mode is set to 0x%x\n", *edc_mode);
        return 0;
 }
 
-
 /* This function read the relevant field from the module ( SFP+ ),
        and verify it is compliant with this board */
-static u8 bnx2x_verify_sfp_module(struct link_params *params,
-                               u8 module_type)
+static u8 bnx2x_verify_sfp_module(struct link_params *params)
 {
        struct bnx2x *bp = params->bp;
-       u8 *str_p, *tmp_buf;
-       u16 i;
-
-#define COMPLIANCE_STR_CNT 6
-       u8 *compliance_str[] = {"Broadcom", "JDSU", "Molex Inc", "PICOLIGHT",
-               "FINISAR CORP.   ", "Amphenol"};
-       u8 buf[SFP_EEPROM_VENDOR_NAME_SIZE];
-       /* Passive Copper cables are allowed to participate,
-       since the module is hardwired to the copper cable */
-
-       if (!(params->feature_config_flags &
-            FEATURE_CONFIG_MODULE_ENFORCMENT_ENABLED)) {
+       u32 val;
+       u32 fw_resp;
+       char vendor_name[SFP_EEPROM_VENDOR_NAME_SIZE+1];
+       char vendor_pn[SFP_EEPROM_PART_NO_SIZE+1];
+
+       val = REG_RD(bp, params->shmem_base +
+                        offsetof(struct shmem_region, dev_info.
+                                 port_feature_config[params->port].config));
+       if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
+           PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_NO_ENFORCEMENT) {
                DP(NETIF_MSG_LINK, "NOT enforcing module verification\n");
                return 0;
        }
 
-       if (module_type != SFP_MODULE_TYPE_LC) {
-               DP(NETIF_MSG_LINK, "No need to verify copper cable\n");
+       /* Ask the FW to validate the module */
+       if (!(params->feature_config_flags &
+             FEATURE_CONFIG_BC_SUPPORTS_OPT_MDL_VRFY)) {
+               DP(NETIF_MSG_LINK, "FW does not support OPT MDL "
+                           "verification\n");
+               return -EINVAL;
+       }
+
+       fw_resp = bnx2x_fw_command(bp, DRV_MSG_CODE_VRFY_OPT_MDL);
+       if (fw_resp == FW_MSG_CODE_VRFY_OPT_MDL_SUCCESS) {
+               DP(NETIF_MSG_LINK, "Approved module\n");
                return 0;
        }
 
-       /* In case of non copper cable or Active copper cable,
-               verify that the SFP+ module is compliant with this board*/
+       /* format the warning message */
        if (bnx2x_read_sfp_module_eeprom(params,
                                       SFP_EEPROM_VENDOR_NAME_ADDR,
                                       SFP_EEPROM_VENDOR_NAME_SIZE,
-                                      buf) != 0) {
-               DP(NETIF_MSG_LINK, "Failed to read Vendor-Name from"
-                           " module EEPROM\n");
-               return -EINVAL;
-       }
-       for (i = 0; i < COMPLIANCE_STR_CNT; i++) {
-               str_p = compliance_str[i];
-               tmp_buf = buf;
-               while (*str_p) {
-                       if ((u8)(*tmp_buf) != (u8)(*str_p))
-                               break;
-                       str_p++;
-                       tmp_buf++;
-               }
+                                      (u8 *)vendor_name))
+               vendor_name[0] = '\0';
+       else
+               vendor_name[SFP_EEPROM_VENDOR_NAME_SIZE] = '\0';
+       if (bnx2x_read_sfp_module_eeprom(params,
+                                      SFP_EEPROM_PART_NO_ADDR,
+                                      SFP_EEPROM_PART_NO_SIZE,
+                                      (u8 *)vendor_pn))
+               vendor_pn[0] = '\0';
+       else
+               vendor_pn[SFP_EEPROM_PART_NO_SIZE] = '\0';
 
-               if (!(*str_p)) {
-                       DP(NETIF_MSG_LINK, "SFP+ Module verified, "
-                                    "index=%x\n", i);
-                       return 0;
-               }
-       }
-       DP(NETIF_MSG_LINK, "Incompliant SFP+ module. Disable module !!!\n");
+       printk(KERN_INFO PFX  "Warning: "
+                        "Unqualified SFP+ module "
+                        "detected on %s, Port %d from %s part number %s\n"
+                       , bp->dev->name, params->port,
+                       vendor_name, vendor_pn);
        return -EINVAL;
 }
 
-
 static u8 bnx2x_bcm8726_set_limiting_mode(struct link_params *params,
-                                       u8 module_type)
+                                       u16 edc_mode)
 {
        struct bnx2x *bp = params->bp;
        u8 port = params->port;
-       u8 options[SFP_EEPROM_OPTIONS_SIZE];
-       u8 limiting_mode;
        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,
-                                      options) != 0) {
-               DP(NETIF_MSG_LINK, "Failed to read Option field from"
-                           " module EEPROM\n");
-               return -EINVAL;
-       }
-       limiting_mode = !(options[0] &
-                         SFP_EEPROM_OPTIONS_LINEAR_RX_OUT_MASK);
 
        bnx2x_cl45_read(bp, port,
                      PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
@@ -2550,26 +2705,23 @@ static u8 bnx2x_bcm8726_set_limiting_mode(struct link_params *params,
        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)) {
+       if (edc_mode == EDC_MODE_LIMITING) {
                DP(NETIF_MSG_LINK,
-                        "Module options = 0x%x.Setting LIMITING MODE\n",
-                        options[0]);
+                        "Setting LIMITING MODE\n");
                bnx2x_cl45_write(bp, port,
                               PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
                               ext_phy_addr,
                               MDIO_PMA_DEVAD,
                               MDIO_PMA_REG_ROM_VER2,
-                              SFP_LIMITING_MODE_VALUE);
+                              EDC_MODE_LIMITING);
        } else { /* LRM mode ( default )*/
 
-               DP(NETIF_MSG_LINK, "Module options = 0x%x.Setting LRM MODE\n",
-                        options[0]);
+               DP(NETIF_MSG_LINK, "Setting LRM MODE\n");
 
                /* Changing to LRM mode takes quite few seconds.
                So do it only if current mode is limiting
                ( default is LRM )*/
-               if (cur_limiting_mode != SFP_LIMITING_MODE_VALUE)
+               if (cur_limiting_mode != EDC_MODE_LIMITING)
                        return 0;
 
                bnx2x_cl45_write(bp, port,
@@ -2600,6 +2752,56 @@ static u8 bnx2x_bcm8726_set_limiting_mode(struct link_params *params,
        return 0;
 }
 
+static u8 bnx2x_bcm8727_set_limiting_mode(struct link_params *params,
+                                       u16 edc_mode)
+{
+       struct bnx2x *bp = params->bp;
+       u8 port = params->port;
+       u16 phy_identifier;
+       u16 rom_ver2_val;
+       u8 ext_phy_addr = ((params->ext_phy_config &
+                           PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
+                          PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
+
+       bnx2x_cl45_read(bp, port,
+                      PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
+                      ext_phy_addr,
+                      MDIO_PMA_DEVAD,
+                      MDIO_PMA_REG_PHY_IDENTIFIER,
+                      &phy_identifier);
+
+       bnx2x_cl45_write(bp, port,
+                      PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
+                      ext_phy_addr,
+                      MDIO_PMA_DEVAD,
+                      MDIO_PMA_REG_PHY_IDENTIFIER,
+                      (phy_identifier & ~(1<<9)));
+
+       bnx2x_cl45_read(bp, port,
+                     PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
+                     ext_phy_addr,
+                     MDIO_PMA_DEVAD,
+                     MDIO_PMA_REG_ROM_VER2,
+                     &rom_ver2_val);
+       /* Keep the MSB 8-bits, and set the LSB 8-bits with the edc_mode */
+       bnx2x_cl45_write(bp, port,
+                      PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
+                      ext_phy_addr,
+                      MDIO_PMA_DEVAD,
+                      MDIO_PMA_REG_ROM_VER2,
+                      (rom_ver2_val & 0xff00) | (edc_mode & 0x00ff));
+
+       bnx2x_cl45_write(bp, port,
+                      PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
+                      ext_phy_addr,
+                      MDIO_PMA_DEVAD,
+                      MDIO_PMA_REG_PHY_IDENTIFIER,
+                      (phy_identifier | (1<<9)));
+
+       return 0;
+}
+
+
 static u8 bnx2x_wait_for_sfp_module_initialized(struct link_params *params)
 {
        u8 val;
@@ -2619,61 +2821,114 @@ static u8 bnx2x_wait_for_sfp_module_initialized(struct link_params *params)
        return -EINVAL;
 }
 
+static void bnx2x_8727_power_module(struct bnx2x *bp,
+                                 struct link_params *params,
+                                 u8 ext_phy_addr, u8 is_power_up) {
+       /* Make sure GPIOs are not using for LED mode */
+       u16 val;
+       u8 port = params->port;
+       /*
+        * In the GPIO register, bit 4 is use to detemine if the GPIOs are
+        * operating as INPUT or as OUTPUT. Bit 1 is for input, and 0 for
+        * output
+        * Bits 0-1 determine the gpios value for OUTPUT in case bit 4 val is 0
+        * Bits 8-9 determine the gpios value for INPUT in case bit 4 val is 1
+        * where the 1st bit is the over-current(only input), and 2nd bit is
+        * for power( only output )
+       */
+
+       /*
+        * In case of NOC feature is disabled and power is up, set GPIO control
+        *  as input to enable listening of over-current indication
+        */
+
+       if (!(params->feature_config_flags &
+             FEATURE_CONFIG_BCM8727_NOC) && is_power_up)
+               val = (1<<4);
+       else
+               /*
+                * Set GPIO control to OUTPUT, and set the power bit
+                * to according to the is_power_up
+                */
+               val = ((!(is_power_up)) << 1);
+
+       bnx2x_cl45_write(bp, port,
+                      PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
+                      ext_phy_addr,
+                      MDIO_PMA_DEVAD,
+                      MDIO_PMA_REG_8727_GPIO_CTRL,
+                      val);
+}
+
 static u8 bnx2x_sfp_module_detection(struct link_params *params)
 {
        struct bnx2x *bp = params->bp;
-       u8 module_type;
+       u16 edc_mode;
+       u8 rc = 0;
        u8 ext_phy_addr = ((params->ext_phy_config &
                                PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
                                PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
        u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
-
-       if (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726) {
-               DP(NETIF_MSG_LINK, "Module detection is not required "
-                           "for this phy\n");
-               return 0;
-       }
+       u32 val = REG_RD(bp, params->shmem_base +
+                            offsetof(struct shmem_region, dev_info.
+                                    port_feature_config[params->port].config));
 
        DP(NETIF_MSG_LINK, "SFP+ module plugged in/out detected on port %d\n",
                 params->port);
 
-       if (bnx2x_get_sfp_module_type(params,
-                                   &module_type) != 0) {
+       if (bnx2x_get_edc_mode(params, &edc_mode) != 0) {
                DP(NETIF_MSG_LINK, "Failed to get valid module type\n");
-               if (!(params->feature_config_flags &
-                     FEATURE_CONFIG_MODULE_ENFORCMENT_ENABLED)) {
-                       /* In case module detection is disabled, it trys to
-                       link up. The issue that can happen here is LRM /
-                       LIMITING mode which set according to the module-type*/
-                       DP(NETIF_MSG_LINK, "Unable to read module-type."
-                                   "Probably due to Bit Stretching."
-                                   " Proceeding...\n");
-               } else {
-                       return -EINVAL;
-               }
-       } else if (bnx2x_verify_sfp_module(params, module_type) !=
+               return -EINVAL;
+       } else if (bnx2x_verify_sfp_module(params) !=
                   0) {
                /* check SFP+ module compatibility */
                DP(NETIF_MSG_LINK, "Module verification failed!!\n");
+               rc = -EINVAL;
                /* Turn on fault module-detected led */
                bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
                                  MISC_REGISTERS_GPIO_HIGH,
                                  params->port);
-               return -EINVAL;
+               if ((ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727) &&
+                   ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
+                    PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_POWER_DOWN)) {
+                       /* Shutdown SFP+ module */
+                       DP(NETIF_MSG_LINK, "Shutdown SFP+ module!!\n");
+                       bnx2x_8727_power_module(bp, params,
+                                             ext_phy_addr, 0);
+                       return rc;
+               }
+       } else {
+               /* Turn off fault module-detected led */
+               DP(NETIF_MSG_LINK, "Turn off fault module-detected led\n");
+               bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
+                                         MISC_REGISTERS_GPIO_LOW,
+                                         params->port);
        }
 
-       /* Turn off fault module-detected led */
-       bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
-                         MISC_REGISTERS_GPIO_LOW,
-                         params->port);
+       /* power up the SFP module */
+       if (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727)
+               bnx2x_8727_power_module(bp, params, ext_phy_addr, 1);
 
-       /* Check and set limiting mode / LRM mode */
-       bnx2x_bcm8726_set_limiting_mode(params, module_type);
+       /* Check and set limiting mode / LRM mode on 8726.
+       On 8727 it is done automatically */
+       if (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726)
+               bnx2x_bcm8726_set_limiting_mode(params, edc_mode);
+       else
+               bnx2x_bcm8727_set_limiting_mode(params, edc_mode);
+       /*
+        * Enable transmit for this module if the module is approved, or
+        * if unapproved modules should also enable the Tx laser
+        */
+       if (rc == 0 ||
+           (val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) !=
+           PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER)
+               bnx2x_sfp_set_transmitter(bp, params->port,
+                                       ext_phy_type, ext_phy_addr, 1);
+       else
+               bnx2x_sfp_set_transmitter(bp, params->port,
+                                       ext_phy_type, ext_phy_addr, 0);
 
-       /* Enable transmit for this module */
-       bnx2x_bcm8726_set_transmitter(bp, params->port,
-                                   ext_phy_addr, 1);
-       return 0;
+       return rc;
 }
 
 void bnx2x_handle_module_detect_int(struct link_params *params)
@@ -2696,8 +2951,8 @@ void bnx2x_handle_module_detect_int(struct link_params *params)
                                      MISC_REGISTERS_GPIO_INT_OUTPUT_CLR,
                                      port);
 
-               if (bnx2x_wait_for_sfp_module_initialized(params)
-                   == 0)
+               if (bnx2x_wait_for_sfp_module_initialized(params) ==
+                   0)
                        bnx2x_sfp_module_detection(params);
                else
                        DP(NETIF_MSG_LINK, "SFP+ module is not initialized\n");
@@ -2705,13 +2960,22 @@ void bnx2x_handle_module_detect_int(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);
+               u32 ext_phy_type =
+                       XGXS_EXT_PHY_TYPE(params->ext_phy_config);
+               u32 val = REG_RD(bp, params->shmem_base +
+                                    offsetof(struct shmem_region, dev_info.
+                                             port_feature_config[params->port].
+                                             config));
+
                bnx2x_set_gpio_int(bp, MISC_REGISTERS_GPIO_3,
                                      MISC_REGISTERS_GPIO_INT_OUTPUT_SET,
                                      port);
                /* Module was plugged out. */
                /* Disable transmit for this module */
-               bnx2x_bcm8726_set_transmitter(bp, params->port,
-                                           ext_phy_addr, 0);
+               if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
+                   PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER)
+                       bnx2x_sfp_set_transmitter(bp, params->port,
+                                               ext_phy_type, ext_phy_addr, 0);
        }
 }
 
@@ -3160,6 +3424,9 @@ static u8 bnx2x_ext_phy_init(struct link_params *params, struct link_vars *vars)
                        driver is loaded, it reset all registers, including the
                        transmitter */
                        bnx2x_sfp_module_detection(params);
+
+                       /* Set Flow control */
+                       bnx2x_ext_phy_set_pause(params, vars);
                        if (params->req_line_speed == SPEED_1000) {
                                DP(NETIF_MSG_LINK, "Setting 1G force\n");
                                bnx2x_cl45_write(bp, params->port, ext_phy_type,
@@ -3450,43 +3717,224 @@ static u8 bnx2x_ext_phy_init(struct link_params *params, struct link_vars *vars)
                           ((val & (1<<7)) > 0));
                        break;
                }
-               case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
+
+               case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
                {
-                       u16 fw_ver1, fw_ver2;
-                       DP(NETIF_MSG_LINK,
-                               "Setting the SFX7101 LASI indication\n");
+                       u16 tmp1;
+                       u16 rx_alarm_ctrl_val;
+                       u16 lasi_ctrl_val;
 
+                       /* Enable PMD link, MOD_ABS_FLT, and 1G link alarm */
+
+                       u16 mod_abs;
+                       rx_alarm_ctrl_val = (1<<2) | (1<<5) ;
+                       lasi_ctrl_val = 0x0004;
+
+                       DP(NETIF_MSG_LINK, "Initializing BCM8727\n");
+                       /* enable LASI */
                        bnx2x_cl45_write(bp, params->port,
                                       ext_phy_type,
                                       ext_phy_addr,
                                       MDIO_PMA_DEVAD,
-                                      MDIO_PMA_REG_LASI_CTRL, 0x1);
-                       DP(NETIF_MSG_LINK,
-                         "Setting the SFX7101 LED to blink on traffic\n");
+                                      MDIO_PMA_REG_RX_ALARM_CTRL,
+                                      rx_alarm_ctrl_val);
+
                        bnx2x_cl45_write(bp, params->port,
                                       ext_phy_type,
                                       ext_phy_addr,
                                       MDIO_PMA_DEVAD,
-                                      MDIO_PMA_REG_7107_LED_CNTL, (1<<3));
+                                      MDIO_PMA_REG_LASI_CTRL,
+                                      lasi_ctrl_val);
 
-                       bnx2x_ext_phy_set_pause(params, vars);
-                       /* Restart autoneg */
+                       /* Initially configure  MOD_ABS to interrupt when
+                       module is presence( bit 8) */
                        bnx2x_cl45_read(bp, params->port,
                                      ext_phy_type,
                                      ext_phy_addr,
-                                     MDIO_AN_DEVAD,
-                                     MDIO_AN_REG_CTRL, &val);
-                       val |= 0x200;
+                                     MDIO_PMA_DEVAD,
+                                     MDIO_PMA_REG_PHY_IDENTIFIER, &mod_abs);
+                       /* Set EDC off by setting OPTXLOS signal input to low
+                       (bit 9).
+                       When the EDC is off it locks onto a reference clock and
+                       avoids becoming 'lost'.*/
+                       mod_abs &= ~((1<<8) | (1<<9));
                        bnx2x_cl45_write(bp, params->port,
                                       ext_phy_type,
                                       ext_phy_addr,
-                                      MDIO_AN_DEVAD,
-                                      MDIO_AN_REG_CTRL, val);
+                                      MDIO_PMA_DEVAD,
+                                      MDIO_PMA_REG_PHY_IDENTIFIER, mod_abs);
 
-                       /* Save spirom version */
-                       bnx2x_cl45_read(bp, params->port, ext_phy_type,
-                                     ext_phy_addr, MDIO_PMA_DEVAD,
-                                     MDIO_PMA_REG_7101_VER1, &fw_ver1);
+                       /* Make MOD_ABS give interrupt on change */
+                       bnx2x_cl45_read(bp, params->port,
+                                     ext_phy_type,
+                                     ext_phy_addr,
+                                     MDIO_PMA_DEVAD,
+                                     MDIO_PMA_REG_8727_PCS_OPT_CTRL,
+                                     &val);
+                       val |= (1<<12);
+                       bnx2x_cl45_write(bp, params->port,
+                                      ext_phy_type,
+                                      ext_phy_addr,
+                                      MDIO_PMA_DEVAD,
+                                      MDIO_PMA_REG_8727_PCS_OPT_CTRL,
+                                      val);
+
+                       /* Set 8727 GPIOs to input to allow reading from the
+                       8727 GPIO0 status which reflect SFP+ module
+                       over-current */
+
+                       bnx2x_cl45_read(bp, params->port,
+                                      PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
+                                      ext_phy_addr,
+                                      MDIO_PMA_DEVAD,
+                                      MDIO_PMA_REG_8727_PCS_OPT_CTRL,
+                                      &val);
+                       val &= 0xff8f; /* Reset bits 4-6 */
+                       bnx2x_cl45_write(bp, params->port,
+                                      PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
+                                      ext_phy_addr,
+                                      MDIO_PMA_DEVAD,
+                                      MDIO_PMA_REG_8727_PCS_OPT_CTRL,
+                                      val);
+
+                       bnx2x_8727_power_module(bp, params, ext_phy_addr, 1);
+                       bnx2x_bcm8073_set_xaui_low_power_mode(params);
+
+                       bnx2x_cl45_read(bp, params->port,
+                                     ext_phy_type,
+                                     ext_phy_addr,
+                                     MDIO_PMA_DEVAD,
+                                     MDIO_PMA_REG_M8051_MSGOUT_REG,
+                                     &tmp1);
+
+                       bnx2x_cl45_read(bp, params->port,
+                                     ext_phy_type,
+                                     ext_phy_addr,
+                                     MDIO_PMA_DEVAD,
+                                     MDIO_PMA_REG_RX_ALARM, &tmp1);
+
+                       /* Set option 1G speed */
+                       if (params->req_line_speed == SPEED_1000) {
+
+                               DP(NETIF_MSG_LINK, "Setting 1G force\n");
+                               bnx2x_cl45_write(bp, params->port,
+                                              ext_phy_type,
+                                              ext_phy_addr,
+                                              MDIO_PMA_DEVAD,
+                                              MDIO_PMA_REG_CTRL, 0x40);
+                               bnx2x_cl45_write(bp, params->port,
+                                              ext_phy_type,
+                                              ext_phy_addr,
+                                              MDIO_PMA_DEVAD,
+                                              MDIO_PMA_REG_10G_CTRL2, 0xD);
+                               bnx2x_cl45_read(bp, params->port,
+                                     ext_phy_type,
+                                     ext_phy_addr,
+                                     MDIO_PMA_DEVAD,
+                                     MDIO_PMA_REG_10G_CTRL2, &tmp1);
+                               DP(NETIF_MSG_LINK, "1.7 = 0x%x \n", tmp1);
+
+                       } else if ((params->req_line_speed ==
+                                   SPEED_AUTO_NEG) &&
+                                  ((params->speed_cap_mask &
+                                    PORT_HW_CFG_SPEED_CAPABILITY_D0_1G))) {
+
+                               DP(NETIF_MSG_LINK, "Setting 1G clause37 \n");
+                               bnx2x_cl45_write(bp, params->port, ext_phy_type,
+                                              ext_phy_addr, MDIO_AN_DEVAD,
+                                              MDIO_PMA_REG_8727_MISC_CTRL, 0);
+                               bnx2x_cl45_write(bp, params->port, ext_phy_type,
+                                              ext_phy_addr, MDIO_AN_DEVAD,
+                                              MDIO_AN_REG_CL37_AN, 0x1300);
+                       } else {
+                               /* Since the 8727 has only single reset pin,
+                               need to set the 10G registers although it is
+                               default */
+                               bnx2x_cl45_write(bp, params->port, ext_phy_type,
+                                              ext_phy_addr, MDIO_AN_DEVAD,
+                                              MDIO_AN_REG_CTRL, 0x0020);
+                               bnx2x_cl45_write(bp, params->port, ext_phy_type,
+                                              ext_phy_addr, MDIO_AN_DEVAD,
+                                              0x7, 0x0100);
+                               bnx2x_cl45_write(bp, params->port, ext_phy_type,
+                                              ext_phy_addr, MDIO_PMA_DEVAD,
+                                              MDIO_PMA_REG_CTRL, 0x2040);
+                               bnx2x_cl45_write(bp, params->port, ext_phy_type,
+                                              ext_phy_addr, MDIO_PMA_DEVAD,
+                                              MDIO_PMA_REG_10G_CTRL2, 0x0008);
+                       }
+
+                       /* Set 2-wire transfer rate to 400Khz since 100Khz
+                       is not operational */
+                       bnx2x_cl45_write(bp, params->port,
+                                      ext_phy_type,
+                                      ext_phy_addr,
+                                      MDIO_PMA_DEVAD,
+                                      MDIO_PMA_REG_8727_TWO_WIRE_SLAVE_ADDR,
+                                      0xa101);
+
+                       /* Set TX PreEmphasis if needed */
+                       if ((params->feature_config_flags &
+                            FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED)) {
+                               DP(NETIF_MSG_LINK, "Setting TX_CTRL1 0x%x,"
+                                        "TX_CTRL2 0x%x\n",
+                                        params->xgxs_config_tx[0],
+                                        params->xgxs_config_tx[1]);
+                               bnx2x_cl45_write(bp, params->port,
+                                              ext_phy_type,
+                                              ext_phy_addr,
+                                              MDIO_PMA_DEVAD,
+                                              MDIO_PMA_REG_8727_TX_CTRL1,
+                                              params->xgxs_config_tx[0]);
+
+                               bnx2x_cl45_write(bp, params->port,
+                                              ext_phy_type,
+                                              ext_phy_addr,
+                                              MDIO_PMA_DEVAD,
+                                              MDIO_PMA_REG_8727_TX_CTRL2,
+                                              params->xgxs_config_tx[1]);
+                       }
+
+                       break;
+               }
+
+               case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
+               {
+                       u16 fw_ver1, fw_ver2;
+                       DP(NETIF_MSG_LINK,
+                               "Setting the SFX7101 LASI indication\n");
+
+                       bnx2x_cl45_write(bp, params->port,
+                                      ext_phy_type,
+                                      ext_phy_addr,
+                                      MDIO_PMA_DEVAD,
+                                      MDIO_PMA_REG_LASI_CTRL, 0x1);
+                       DP(NETIF_MSG_LINK,
+                         "Setting the SFX7101 LED to blink on traffic\n");
+                       bnx2x_cl45_write(bp, params->port,
+                                      ext_phy_type,
+                                      ext_phy_addr,
+                                      MDIO_PMA_DEVAD,
+                                      MDIO_PMA_REG_7107_LED_CNTL, (1<<3));
+
+                       bnx2x_ext_phy_set_pause(params, vars);
+                       /* Restart autoneg */
+                       bnx2x_cl45_read(bp, params->port,
+                                     ext_phy_type,
+                                     ext_phy_addr,
+                                     MDIO_AN_DEVAD,
+                                     MDIO_AN_REG_CTRL, &val);
+                       val |= 0x200;
+                       bnx2x_cl45_write(bp, params->port,
+                                      ext_phy_type,
+                                      ext_phy_addr,
+                                      MDIO_AN_DEVAD,
+                                      MDIO_AN_REG_CTRL, val);
+
+                       /* Save spirom version */
+                       bnx2x_cl45_read(bp, params->port, ext_phy_type,
+                                     ext_phy_addr, MDIO_PMA_DEVAD,
+                                     MDIO_PMA_REG_7101_VER1, &fw_ver1);
 
                        bnx2x_cl45_read(bp, params->port, ext_phy_type,
                                      ext_phy_addr, MDIO_PMA_DEVAD,
@@ -3561,6 +4009,99 @@ static u8 bnx2x_ext_phy_init(struct link_params *params, struct link_vars *vars)
        return rc;
 }
 
+static void bnx2x_8727_handle_mod_abs(struct link_params *params)
+{
+       struct bnx2x *bp = params->bp;
+       u16 mod_abs, rx_alarm_status;
+       u8 ext_phy_addr = ((params->ext_phy_config &
+                           PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
+                          PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
+       u32 val = REG_RD(bp, params->shmem_base +
+                            offsetof(struct shmem_region, dev_info.
+                                     port_feature_config[params->port].
+                                     config));
+       bnx2x_cl45_read(bp, params->port,
+                     PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
+                     ext_phy_addr,
+                     MDIO_PMA_DEVAD,
+                     MDIO_PMA_REG_PHY_IDENTIFIER, &mod_abs);
+       if (mod_abs & (1<<8)) {
+
+               /* Module is absent */
+               DP(NETIF_MSG_LINK, "MOD_ABS indication "
+                           "show module is absent\n");
+
+               /* 1. Set mod_abs to detect next module
+               presence event
+                  2. Set EDC off by setting OPTXLOS signal input to low
+                       (bit 9).
+                       When the EDC is off it locks onto a reference clock and
+                       avoids becoming 'lost'.*/
+               mod_abs &= ~((1<<8)|(1<<9));
+               bnx2x_cl45_write(bp, params->port,
+                              PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
+                              ext_phy_addr,
+                              MDIO_PMA_DEVAD,
+                              MDIO_PMA_REG_PHY_IDENTIFIER, mod_abs);
+
+               /* Clear RX alarm since it stays up as long as
+               the mod_abs wasn't changed */
+               bnx2x_cl45_read(bp, params->port,
+                             PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
+                             ext_phy_addr,
+                             MDIO_PMA_DEVAD,
+                             MDIO_PMA_REG_RX_ALARM, &rx_alarm_status);
+
+       } else {
+               /* Module is present */
+               DP(NETIF_MSG_LINK, "MOD_ABS indication "
+                           "show module is present\n");
+               /* First thing, disable transmitter,
+               and if the module is ok, the
+               module_detection will enable it*/
+
+               /* 1. Set mod_abs to detect next module
+               absent event ( bit 8)
+                  2. Restore the default polarity of the OPRXLOS signal and
+               this signal will then correctly indicate the presence or
+               absence of the Rx signal. (bit 9) */
+               mod_abs |= ((1<<8)|(1<<9));
+               bnx2x_cl45_write(bp, params->port,
+                      PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
+                      ext_phy_addr,
+                      MDIO_PMA_DEVAD,
+                      MDIO_PMA_REG_PHY_IDENTIFIER, mod_abs);
+
+               /* Clear RX alarm since it stays up as long as
+               the mod_abs wasn't changed. This is need to be done
+               before calling the module detection, otherwise it will clear
+               the link update alarm */
+               bnx2x_cl45_read(bp, params->port,
+                             PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
+                             ext_phy_addr,
+                             MDIO_PMA_DEVAD,
+                             MDIO_PMA_REG_RX_ALARM, &rx_alarm_status);
+
+
+               if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
+                   PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER)
+                       bnx2x_sfp_set_transmitter(bp, params->port,
+                                       PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
+                                       ext_phy_addr, 0);
+
+               if (bnx2x_wait_for_sfp_module_initialized(params)
+                   == 0)
+                       bnx2x_sfp_module_detection(params);
+               else
+                       DP(NETIF_MSG_LINK, "SFP+ module is not initialized\n");
+       }
+
+       DP(NETIF_MSG_LINK, "8727 RX_ALARM_STATUS 0x%x\n",
+                rx_alarm_status);
+       /* No need to check link status in case of
+       module plugged in/out */
+}
+
 
 static u8 bnx2x_ext_phy_is_link_up(struct link_params *params,
                                 struct link_vars *vars)
@@ -3602,8 +4143,19 @@ static u8 bnx2x_ext_phy_is_link_up(struct link_params *params,
                                      ext_phy_addr,
                                      MDIO_PMA_DEVAD,
                                      MDIO_PMA_REG_RX_SD, &rx_sd);
-                       DP(NETIF_MSG_LINK, "8705 rx_sd 0x%x\n", rx_sd);
-                       ext_phy_link_up = (rx_sd & 0x1);
+
+                       bnx2x_cl45_read(bp, params->port, ext_phy_type,
+                                     ext_phy_addr,
+                                     1,
+                                     0xc809, &val1);
+                       bnx2x_cl45_read(bp, params->port, ext_phy_type,
+                                     ext_phy_addr,
+                                     1,
+                                     0xc809, &val1);
+
+                       DP(NETIF_MSG_LINK, "8705 1.c809 val=0x%x\n", val1);
+                       ext_phy_link_up = ((rx_sd & 0x1) && (val1 & (1<<9))
+                                          && ((val1 & (1<<8)) == 0));
                        if (ext_phy_link_up)
                                vars->line_speed = SPEED_10000;
                        break;
@@ -3678,8 +4230,160 @@ static u8 bnx2x_ext_phy_is_link_up(struct link_params *params,
                                else
                                        vars->line_speed = SPEED_10000;
                        }
+                       break;
+
+               case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
+               {
+                       u16 link_status = 0;
+                       u16 rx_alarm_status;
+                       /* Check the LASI */
+                       bnx2x_cl45_read(bp, params->port,
+                                     ext_phy_type,
+                                     ext_phy_addr,
+                                     MDIO_PMA_DEVAD,
+                                     MDIO_PMA_REG_RX_ALARM, &rx_alarm_status);
+
+                       DP(NETIF_MSG_LINK, "8727 RX_ALARM_STATUS 0x%x\n",
+                                rx_alarm_status);
+
+                       bnx2x_cl45_read(bp, params->port,
+                                     ext_phy_type,
+                                     ext_phy_addr,
+                                     MDIO_PMA_DEVAD,
+                                     MDIO_PMA_REG_LASI_STATUS, &val1);
 
+                       DP(NETIF_MSG_LINK,
+                                "8727 LASI status 0x%x\n",
+                                val1);
+
+                       /* Clear MSG-OUT */
+                       bnx2x_cl45_read(bp, params->port,
+                                     ext_phy_type,
+                                     ext_phy_addr,
+                                     MDIO_PMA_DEVAD,
+                                     MDIO_PMA_REG_M8051_MSGOUT_REG,
+                                     &val1);
+
+                       /*
+                        * If a module is present and there is need to check
+                        * for over current
+                        */
+                       if (!(params->feature_config_flags &
+                             FEATURE_CONFIG_BCM8727_NOC) &&
+                           !(rx_alarm_status & (1<<5))) {
+                               /* Check over-current using 8727 GPIO0 input*/
+                               bnx2x_cl45_read(bp, params->port,
+                                             ext_phy_type,
+                                             ext_phy_addr,
+                                             MDIO_PMA_DEVAD,
+                                             MDIO_PMA_REG_8727_GPIO_CTRL,
+                                             &val1);
+
+                               if ((val1 & (1<<8)) == 0) {
+                                       DP(NETIF_MSG_LINK, "8727 Power fault"
+                                                " has been detected on port"
+                                                " %d\n", params->port);
+                                       printk(KERN_ERR PFX  "Error:  Power"
+                                                " fault on %s Port %d has"
+                                                " been detected and the"
+                                                " power to that SFP+ module"
+                                                " has been removed to prevent"
+                                                " failure of the card. Please"
+                                                " remove the SFP+ module and"
+                                                " restart the system to clear"
+                                                " this error.\n"
+                       , bp->dev->name, params->port);
+                                       /*
+                                        * Disable all RX_ALARMs except for
+                                        * mod_abs
+                                        */
+                                       bnx2x_cl45_write(bp, params->port,
+                                                    ext_phy_type,
+                                                    ext_phy_addr,
+                                                    MDIO_PMA_DEVAD,
+                                                    MDIO_PMA_REG_RX_ALARM_CTRL,
+                                                    (1<<5));
+
+                                       bnx2x_cl45_read(bp, params->port,
+                                                   ext_phy_type,
+                                                   ext_phy_addr,
+                                                   MDIO_PMA_DEVAD,
+                                                   MDIO_PMA_REG_PHY_IDENTIFIER,
+                                                   &val1);
+                                       /* Wait for module_absent_event */
+                                       val1 |= (1<<8);
+                                       bnx2x_cl45_write(bp, params->port,
+                                                   ext_phy_type,
+                                                   ext_phy_addr,
+                                                   MDIO_PMA_DEVAD,
+                                                   MDIO_PMA_REG_PHY_IDENTIFIER,
+                                                   val1);
+                                       /* Clear RX alarm */
+                                       bnx2x_cl45_read(bp, params->port,
+                                                     ext_phy_type,
+                                                     ext_phy_addr,
+                                                     MDIO_PMA_DEVAD,
+                                                     MDIO_PMA_REG_RX_ALARM,
+                                                     &rx_alarm_status);
+                                       break;
+                               }
+                       } /* Over current check */
+
+                       /* When module absent bit is set, check module */
+                       if (rx_alarm_status & (1<<5)) {
+                               bnx2x_8727_handle_mod_abs(params);
+                               /* Enable all mod_abs and link detection bits */
+                               bnx2x_cl45_write(bp, params->port,
+                                              ext_phy_type,
+                                              ext_phy_addr,
+                                              MDIO_PMA_DEVAD,
+                                              MDIO_PMA_REG_RX_ALARM_CTRL,
+                                              ((1<<5) | (1<<2)));
+                       }
+
+                       /* If transmitter is disabled,
+                       ignore false link up indication */
+                       bnx2x_cl45_read(bp, params->port,
+                                     ext_phy_type,
+                                     ext_phy_addr,
+                                     MDIO_PMA_DEVAD,
+                                     MDIO_PMA_REG_PHY_IDENTIFIER,
+                                     &val1);
+                       if (val1 & (1<<15)) {
+                               DP(NETIF_MSG_LINK, "Tx is disabled\n");
+                               ext_phy_link_up = 0;
+                               break;
+                       }
+
+                       bnx2x_cl45_read(bp, params->port,
+                                     ext_phy_type,
+                                     ext_phy_addr,
+                                     MDIO_PMA_DEVAD,
+                                     MDIO_PMA_REG_8073_SPEED_LINK_STATUS,
+                                     &link_status);
+
+                       /* Bits 0..2 --> speed detected,
+                          bits 13..15--> link is down */
+                       if ((link_status & (1<<2)) &&
+                           (!(link_status & (1<<15)))) {
+                               ext_phy_link_up = 1;
+                               vars->line_speed = SPEED_10000;
+                       } else if ((link_status & (1<<0)) &&
+                                  (!(link_status & (1<<13)))) {
+                               ext_phy_link_up = 1;
+                               vars->line_speed = SPEED_1000;
+                               DP(NETIF_MSG_LINK,
+                                        "port %x: External link"
+                                        " up in 1G\n", params->port);
+                       } else {
+                               ext_phy_link_up = 0;
+                               DP(NETIF_MSG_LINK,
+                                        "port %x: External link"
+                                        " is down\n", params->port);
+                       }
                        break;
+               }
+
                case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
                case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
                {
@@ -4242,6 +4946,7 @@ u8 bnx2x_get_ext_phy_fw_version(struct link_params *params, u8 driver_loaded,
                break;
        case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
        case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
+       case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
        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:
@@ -4790,6 +5495,11 @@ u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars)
                }
                REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE +
                            params->port*4, 0);
+
+               bnx2x_set_led(bp, params->port, LED_MODE_OPER,
+                           vars->line_speed, params->hw_led_mode,
+                           params->chip_id);
+
        } else
        /* No loopback */
        {
@@ -4843,10 +5553,6 @@ static void bnx2x_8726_reset_phy(struct bnx2x *bp, u8 port, u8 ext_phy_addr)
                       PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726, ext_phy_addr,
                       MDIO_PMA_DEVAD,
                       MDIO_PMA_REG_GEN_CTRL, 0x0001);
-
-       /* Disable Transmitter */
-       bnx2x_bcm8726_set_transmitter(bp, port, ext_phy_addr, 0);
-
 }
 
 u8 bnx2x_link_reset(struct link_params *params, struct link_vars *vars,
@@ -4859,6 +5565,11 @@ u8 bnx2x_link_reset(struct link_params *params, struct link_vars *vars,
        u32 chip_id = params->chip_id;
        u8 port = params->port;
        u32 ext_phy_type = XGXS_EXT_PHY_TYPE(ext_phy_config);
+       u32 val = REG_RD(bp, params->shmem_base +
+                            offsetof(struct shmem_region, dev_info.
+                                     port_feature_config[params->port].
+                                     config));
+
        /* disable attentions */
 
        vars->link_status = 0;
@@ -4893,6 +5604,21 @@ u8 bnx2x_link_reset(struct link_params *params, struct link_vars *vars,
                case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
                case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
                        break;
+
+               case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
+               {
+
+                       /* Disable Transmitter */
+                       u8 ext_phy_addr = ((params->ext_phy_config &
+                                   PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
+                                  PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
+                       if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
+                           PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER)
+                               bnx2x_sfp_set_transmitter(bp, port,
+                                       PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
+                                       ext_phy_addr, 0);
+                       break;
+               }
                case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
                        DP(NETIF_MSG_LINK, "Setting 8073 port %d into "
                                 "low power mode\n",
@@ -5217,6 +5943,74 @@ static u8 bnx2x_8073_common_init_phy(struct bnx2x *bp, u32 shmem_base)
 
 }
 
+static u8 bnx2x_8727_common_init_phy(struct bnx2x *bp, u32 shmem_base)
+{
+       u8 ext_phy_addr[PORT_MAX];
+       s8 port;
+       u32 swap_val, swap_override;
+       DP(NETIF_MSG_LINK, "Executing BCM8727 common init\n");
+       swap_val = REG_RD(bp,  NIG_REG_PORT_SWAP);
+       swap_override = REG_RD(bp,  NIG_REG_STRAP_OVERRIDE);
+
+       bnx2x_hw_reset(bp, 1 ^ (swap_val && swap_override));
+       msleep(5);
+
+       /* PART1 - Reset both phys */
+       for (port = PORT_MAX - 1; port >= PORT_0; port--) {
+               /* Extract the ext phy address for the port */
+               u32 ext_phy_config = REG_RD(bp, shmem_base +
+                                       offsetof(struct shmem_region,
+                  dev_info.port_hw_config[port].external_phy_config));
+
+               /* disable attentions */
+               bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
+                            (NIG_MASK_XGXS0_LINK_STATUS |
+                             NIG_MASK_XGXS0_LINK10G |
+                             NIG_MASK_SERDES0_LINK_STATUS |
+                             NIG_MASK_MI_INT));
+
+               ext_phy_addr[port] = ((ext_phy_config &
+                                       PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
+                                       PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
+
+               /* Reset the phy */
+               bnx2x_cl45_write(bp, port,
+                              PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
+                              ext_phy_addr[port],
+                              MDIO_PMA_DEVAD,
+                              MDIO_PMA_REG_CTRL,
+                              1<<15);
+       }
+
+       /* Add delay of 150ms after reset */
+       msleep(150);
+
+       /* PART2 - Download firmware to both phys */
+       for (port = PORT_MAX - 1; port >= PORT_0; port--) {
+               u16 fw_ver1;
+
+               bnx2x_bcm8727_external_rom_boot(bp, port,
+                                             ext_phy_addr[port], shmem_base);
+
+               bnx2x_cl45_read(bp, port, PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
+                             ext_phy_addr[port],
+                             MDIO_PMA_DEVAD,
+                             MDIO_PMA_REG_ROM_VER1, &fw_ver1);
+               if (fw_ver1 == 0 || fw_ver1 == 0x4321) {
+                       DP(NETIF_MSG_LINK,
+                                "bnx2x_8073_common_init_phy port %x:"
+                                "Download failed. fw version = 0x%x\n",
+                                port, fw_ver1);
+                       return -EINVAL;
+               }
+
+       }
+
+
+
+       return 0;
+}
+
 
 static u8 bnx2x_8726_common_init_phy(struct bnx2x *bp, u32 shmem_base)
 {
@@ -5275,6 +6069,12 @@ u8 bnx2x_common_init_phy(struct bnx2x *bp, u32 shmem_base)
                rc = bnx2x_8073_common_init_phy(bp, shmem_base);
                break;
        }
+
+       case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
+       case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727_NOC:
+               rc = bnx2x_8727_common_init_phy(bp, shmem_base);
+               break;
+
        case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
                /* GPIO1 affects both ports, so there's need to pull
                it for single port alone */
index 19a866d..d25ef45 100644 (file)
 #define SPEED_15000            15000
 #define SPEED_16000            16000
 
-
+#define SFP_EEPROM_VENDOR_NAME_ADDR            0x14
+#define SFP_EEPROM_VENDOR_NAME_SIZE            16
+#define SFP_EEPROM_VENDOR_OUI_ADDR             0x25
+#define SFP_EEPROM_VENDOR_OUI_SIZE             3
+#define SFP_EEPROM_PART_NO_ADDR                0x28
+#define SFP_EEPROM_PART_NO_SIZE                16
+#define PWR_FLT_ERR_MSG_LEN                    250
 /***********************************************************/
 /*                         Structs                         */
 /***********************************************************/
@@ -91,7 +97,8 @@ struct link_params {
        u16 xgxs_config_tx[4]; /* preemphasis values for the tx side */
        u32 feature_config_flags;
 #define FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED (1<<0)
-#define FEATURE_CONFIG_MODULE_ENFORCMENT_ENABLED       (2<<0)
+#define FEATURE_CONFIG_BC_SUPPORTS_OPT_MDL_VRFY        (1<<2)
+#define FEATURE_CONFIG_BCM8727_NOC                     (1<<3)
        /* Device pointer passed to all callback functions */
        struct bnx2x *bp;
 };
@@ -181,4 +188,7 @@ u8 bnx2x_test_link(struct link_params *input, struct link_vars *vars);
 u8 bnx2x_common_init_phy(struct bnx2x *bp, u32 shmem_base);
 
 
+u8 bnx2x_read_sfp_module_eeprom(struct link_params *params, u16 addr,
+                             u8 byte_cnt, u8 *o_buf);
+
 #endif /* BNX2X_LINK_H */
index 6c67be6..c4c42b3 100644 (file)
@@ -56,8 +56,8 @@
 #include "bnx2x_init_ops.h"
 #include "bnx2x_dump.h"
 
-#define DRV_MODULE_VERSION     "1.48.105-1"
-#define DRV_MODULE_RELDATE     "2009/04/22"
+#define DRV_MODULE_VERSION     "1.48.113-1"
+#define DRV_MODULE_RELDATE     "2009/07/21"
 #define BNX2X_BC_VER           0x040200
 
 #include <linux/firmware.h>
@@ -652,6 +652,11 @@ static void bnx2x_int_enable(struct bnx2x *bp)
           val, port, addr, (msix ? "MSI-X" : (msi ? "MSI" : "INTx")));
 
        REG_WR(bp, addr, val);
+       /*
+        * Ensure that HC_CONFIG is written before leading/trailing edge config
+        */
+       mmiowb();
+       barrier();
 
        if (CHIP_IS_E1H(bp)) {
                /* init leading/trailing edge */
@@ -666,6 +671,9 @@ static void bnx2x_int_enable(struct bnx2x *bp)
                REG_WR(bp, HC_REG_TRAILING_EDGE_0 + port*8, val);
                REG_WR(bp, HC_REG_LEADING_EDGE_0 + port*8, val);
        }
+
+       /* Make sure that interrupts are indeed enabled from here on */
+       mmiowb();
 }
 
 static void bnx2x_int_disable(struct bnx2x *bp)
@@ -698,6 +706,8 @@ static void bnx2x_int_disable_sync(struct bnx2x *bp, int disable_hw)
 
        /* disable interrupt handling */
        atomic_inc(&bp->intr_sem);
+       smp_wmb(); /* Ensure that bp->intr_sem update is SMP-safe */
+
        if (disable_hw)
                /* prevent the HW from sending interrupts */
                bnx2x_int_disable(bp);
@@ -739,6 +749,10 @@ static inline void bnx2x_ack_sb(struct bnx2x *bp, u8 sb_id,
        DP(BNX2X_MSG_OFF, "write 0x%08x to HC addr 0x%x\n",
           (*(u32 *)&igu_ack), hc_addr);
        REG_WR(bp, hc_addr, (*(u32 *)&igu_ack));
+
+       /* Make sure that ACK is written */
+       mmiowb();
+       barrier();
 }
 
 static inline u16 bnx2x_update_fpsb_idx(struct bnx2x_fastpath *fp)
@@ -2429,9 +2443,14 @@ static int bnx2x_sp_post(struct bnx2x *bp, int command, int cid,
                bp->spq_prod_idx++;
        }
 
+       /* Make sure that BD data is updated before writing the producer */
+       wmb();
+
        REG_WR(bp, BAR_XSTRORM_INTMEM + XSTORM_SPQ_PROD_OFFSET(func),
               bp->spq_prod_idx);
 
+       mmiowb();
+
        spin_unlock_bh(&bp->spq_lock);
        return 0;
 }
@@ -2598,11 +2617,27 @@ static void bnx2x_attn_int_asserted(struct bnx2x *bp, u32 asserted)
        }
 }
 
+static inline void bnx2x_fan_failure(struct bnx2x *bp)
+{
+       int port = BP_PORT(bp);
+
+       /* mark the failure */
+       bp->link_params.ext_phy_config &= ~PORT_HW_CFG_XGXS_EXT_PHY_TYPE_MASK;
+       bp->link_params.ext_phy_config |= PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE;
+       SHMEM_WR(bp, dev_info.port_hw_config[port].external_phy_config,
+                bp->link_params.ext_phy_config);
+
+       /* log the failure */
+       printk(KERN_ERR PFX "Fan Failure on Network Controller %s has caused"
+              " the driver to shutdown the card to prevent permanent"
+              " damage.  Please contact Dell Support for assistance\n",
+              bp->dev->name);
+}
 static inline void bnx2x_attn_int_deasserted0(struct bnx2x *bp, u32 attn)
 {
        int port = BP_PORT(bp);
        int reg_offset;
-       u32 val;
+       u32 val, swap_val, swap_override;
 
        reg_offset = (port ? MISC_REG_AEU_ENABLE1_FUNC_1_OUT_0 :
                             MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0);
@@ -2615,36 +2650,32 @@ static inline void bnx2x_attn_int_deasserted0(struct bnx2x *bp, u32 attn)
 
                BNX2X_ERR("SPIO5 hw attention\n");
 
+               /* Fan failure attention */
                switch (XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config)) {
                case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
-                       /* Fan failure attention */
-
+                       /* Low power mode is controlled by GPIO 2 */
+                       bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
+                                      MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
                        /* The PHY reset is controlled by GPIO 1 */
                        bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
                                       MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
-                       /* Low power mode is controlled by GPIO 2 */
-                       bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
+                       break;
+
+               case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
+                       /* The PHY reset is controlled by GPIO 1 */
+                       /* fake the port number to cancel the swap done in
+                          set_gpio() */
+                       swap_val = REG_RD(bp, NIG_REG_PORT_SWAP);
+                       swap_override = REG_RD(bp, NIG_REG_STRAP_OVERRIDE);
+                       port = (swap_val && swap_override) ^ 1;
+                       bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
                                       MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
-                       /* mark the failure */
-                       bp->link_params.ext_phy_config &=
-                                       ~PORT_HW_CFG_XGXS_EXT_PHY_TYPE_MASK;
-                       bp->link_params.ext_phy_config |=
-                                       PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE;
-                       SHMEM_WR(bp,
-                                dev_info.port_hw_config[port].
-                                                       external_phy_config,
-                                bp->link_params.ext_phy_config);
-                       /* log the failure */
-                       printk(KERN_ERR PFX "Fan Failure on Network"
-                              " Controller %s has caused the driver to"
-                              " shutdown the card to prevent permanent"
-                              " damage.  Please contact Dell Support for"
-                              " assistance\n", bp->dev->name);
                        break;
 
                default:
                        break;
                }
+               bnx2x_fan_failure(bp);
        }
 
        if (attn & (AEU_INPUTS_ATTN_BITS_GPIO3_FUNCTION_0 |
@@ -5184,6 +5215,11 @@ static void bnx2x_nic_init(struct bnx2x *bp, u32 load_code)
        mmiowb();
 
        bnx2x_int_enable(bp);
+
+       /* Check for SPIO5 */
+       bnx2x_attn_int_deasserted0(bp,
+               REG_RD(bp, MISC_REG_AEU_AFTER_INVERT_1_FUNC_0 + BP_PORT(bp)*4) &
+                                  AEU_INPUTS_ATTN_BITS_SPIO5);
 }
 
 /* end of nic init */
@@ -5509,6 +5545,60 @@ static void bnx2x_reset_common(struct bnx2x *bp)
        REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR, 0x1403);
 }
 
+
+static void bnx2x_setup_fan_failure_detection(struct bnx2x *bp)
+{
+       u32 val;
+       u8 port;
+       u8 is_required = 0;
+
+       val = SHMEM_RD(bp, dev_info.shared_hw_config.config2) &
+             SHARED_HW_CFG_FAN_FAILURE_MASK;
+
+       if (val == SHARED_HW_CFG_FAN_FAILURE_ENABLED)
+               is_required = 1;
+
+       /*
+        * The fan failure mechanism is usually related to the PHY type since
+        * the power consumption of the board is affected by the PHY. Currently,
+        * fan is required for most designs with SFX7101, BCM8727 and BCM8481.
+        */
+       else if (val == SHARED_HW_CFG_FAN_FAILURE_PHY_TYPE)
+               for (port = PORT_0; port < PORT_MAX; port++) {
+                       u32 phy_type =
+                               SHMEM_RD(bp, dev_info.port_hw_config[port].
+                                        external_phy_config) &
+                               PORT_HW_CFG_XGXS_EXT_PHY_TYPE_MASK;
+                       is_required |=
+                               ((phy_type ==
+                                 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101) ||
+                                (phy_type ==
+                                 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727) ||
+                                (phy_type ==
+                                 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481));
+               }
+
+       DP(NETIF_MSG_HW, "fan detection setting: %d\n", is_required);
+
+       if (is_required == 0)
+               return;
+
+       /* Fan failure is indicated by SPIO 5 */
+       bnx2x_set_spio(bp, MISC_REGISTERS_SPIO_5,
+                      MISC_REGISTERS_SPIO_INPUT_HI_Z);
+
+       /* set to active low mode */
+       val = REG_RD(bp, MISC_REG_SPIO_INT);
+       val |= ((1 << MISC_REGISTERS_SPIO_5) <<
+                               MISC_REGISTERS_SPIO_INT_OLD_SET_POS);
+       REG_WR(bp, MISC_REG_SPIO_INT, val);
+
+       /* enable interrupt to signal the IGU */
+       val = REG_RD(bp, MISC_REG_SPIO_EVENT_EN);
+       val |= (1 << MISC_REGISTERS_SPIO_5);
+       REG_WR(bp, MISC_REG_SPIO_EVENT_EN, val);
+}
+
 static int bnx2x_init_common(struct bnx2x *bp)
 {
        u32 val, i;
@@ -5735,30 +5825,16 @@ static int bnx2x_init_common(struct bnx2x *bp)
        case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
        case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
        case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
+       case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
                bp->port.need_hw_lock = 1;
                break;
 
-       case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
-               /* Fan failure is indicated by SPIO 5 */
-               bnx2x_set_spio(bp, MISC_REGISTERS_SPIO_5,
-                              MISC_REGISTERS_SPIO_INPUT_HI_Z);
-
-               /* set to active low mode */
-               val = REG_RD(bp, MISC_REG_SPIO_INT);
-               val |= ((1 << MISC_REGISTERS_SPIO_5) <<
-                                       MISC_REGISTERS_SPIO_INT_OLD_SET_POS);
-               REG_WR(bp, MISC_REG_SPIO_INT, val);
-
-               /* enable interrupt to signal the IGU */
-               val = REG_RD(bp, MISC_REG_SPIO_EVENT_EN);
-               val |= (1 << MISC_REGISTERS_SPIO_5);
-               REG_WR(bp, MISC_REG_SPIO_EVENT_EN, val);
-               break;
-
        default:
                break;
        }
 
+       bnx2x_setup_fan_failure_detection(bp);
+
        /* clear PXP2 attentions */
        REG_RD(bp, PXP2_REG_PXP2_INT_STS_CLR_0);
 
@@ -5988,10 +6064,15 @@ static int bnx2x_init_port(struct bnx2x *bp)
                break;
 
        case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
+       case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
                /* add SPIO 5 to group 0 */
-               val = REG_RD(bp, MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0);
+               {
+               u32 reg_addr = (port ? MISC_REG_AEU_ENABLE1_FUNC_1_OUT_0 :
+                                      MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0);
+               val = REG_RD(bp, reg_addr);
                val |= AEU_INPUTS_ATTN_BITS_SPIO5;
-               REG_WR(bp, MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0, val);
+               REG_WR(bp, reg_addr, val);
+               }
                break;
 
        default:
@@ -6141,7 +6222,7 @@ init_hw_err:
 }
 
 /* send the MCP a request, block until there is a reply */
-static u32 bnx2x_fw_command(struct bnx2x *bp, u32 command)
+u32 bnx2x_fw_command(struct bnx2x *bp, u32 command)
 {
        int func = BP_FUNC(bp);
        u32 seq = ++bp->fw_seq;
@@ -6582,7 +6663,12 @@ static void bnx2x_napi_disable(struct bnx2x *bp)
 
 static void bnx2x_netif_start(struct bnx2x *bp)
 {
-       if (atomic_dec_and_test(&bp->intr_sem)) {
+       int intr_sem;
+
+       intr_sem = atomic_dec_and_test(&bp->intr_sem);
+       smp_wmb(); /* Ensure that bp->intr_sem update is SMP-safe */
+
+       if (intr_sem) {
                if (netif_running(bp->dev)) {
                        bnx2x_napi_enable(bp);
                        bnx2x_int_enable(bp);
@@ -7609,6 +7695,9 @@ static void __devinit bnx2x_get_common_hwinfo(struct bnx2x *bp)
                BNX2X_ERR("This driver needs bc_ver %X but found %X,"
                          " please upgrade BC\n", BNX2X_BC_VER, val);
        }
+       bp->link_params.feature_config_flags |=
+               (val >= REQ_BC_VER_4_VRFY_OPT_MDL) ?
+               FEATURE_CONFIG_BC_SUPPORTS_OPT_MDL_VRFY : 0;
 
        if (BP_E1HVN(bp) == 0) {
                pci_read_config_word(bp->pdev, bp->pm_cap + PCI_PM_PMC, &pmc);
@@ -7769,6 +7858,18 @@ static void __devinit bnx2x_link_settings_supported(struct bnx2x *bp,
                                               SUPPORTED_Asym_Pause);
                        break;
 
+               case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
+                       BNX2X_DEV_INFO("ext_phy_type 0x%x (8727)\n",
+                                      ext_phy_type);
+
+                       bp->port.supported |= (SUPPORTED_10000baseT_Full |
+                                              SUPPORTED_1000baseT_Full |
+                                              SUPPORTED_Autoneg |
+                                              SUPPORTED_FIBRE |
+                                              SUPPORTED_Pause |
+                                              SUPPORTED_Asym_Pause);
+                       break;
+
                case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
                        BNX2X_DEV_INFO("ext_phy_type 0x%x (SFX7101)\n",
                                       ext_phy_type);
@@ -8032,6 +8133,17 @@ static void __devinit bnx2x_get_port_hwinfo(struct bnx2x *bp)
        bp->link_params.ext_phy_config =
                SHMEM_RD(bp,
                         dev_info.port_hw_config[port].external_phy_config);
+       /* BCM8727_NOC => BCM8727 no over current */
+       if (XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config) ==
+           PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727_NOC) {
+               bp->link_params.ext_phy_config &=
+                       ~PORT_HW_CFG_XGXS_EXT_PHY_TYPE_MASK;
+               bp->link_params.ext_phy_config |=
+                       PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727;
+               bp->link_params.feature_config_flags |=
+                       FEATURE_CONFIG_BCM8727_NOC;
+       }
+
        bp->link_params.speed_cap_mask =
                SHMEM_RD(bp,
                         dev_info.port_hw_config[port].speed_capability_mask);
@@ -8052,17 +8164,10 @@ static void __devinit bnx2x_get_port_hwinfo(struct bnx2x *bp)
                bp->link_params.xgxs_config_tx[(i << 1) + 1] = (val & 0xffff);
        }
 
-       config = SHMEM_RD(bp, dev_info.port_feature_config[port].config);
-       if (config & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_ENABLED)
-               bp->link_params.feature_config_flags |=
-                               FEATURE_CONFIG_MODULE_ENFORCMENT_ENABLED;
-       else
-               bp->link_params.feature_config_flags &=
-                               ~FEATURE_CONFIG_MODULE_ENFORCMENT_ENABLED;
-
        /* If the device is capable of WoL, set the default state according
         * to the HW
         */
+       config = SHMEM_RD(bp, dev_info.port_feature_config[port].config);
        bp->wol = (!(bp->flags & NO_WOL_FLAG) &&
                   (config & PORT_FEATURE_WOL_ENABLED));
 
@@ -8072,8 +8177,8 @@ static void __devinit bnx2x_get_port_hwinfo(struct bnx2x *bp)
                       bp->link_params.ext_phy_config,
                       bp->link_params.speed_cap_mask, bp->port.link_config);
 
-       bp->link_params.switch_cfg = (bp->port.link_config &
-                                     PORT_FEATURE_CONNECTED_SWITCH_MASK);
+       bp->link_params.switch_cfg |= (bp->port.link_config &
+                                      PORT_FEATURE_CONNECTED_SWITCH_MASK);
        bnx2x_link_settings_supported(bp, bp->link_params.switch_cfg);
 
        bnx2x_link_settings_requested(bp);
@@ -8169,6 +8274,7 @@ static int __devinit bnx2x_init_bp(struct bnx2x *bp)
 
        /* Disable interrupt handling until HW is initialized */
        atomic_set(&bp->intr_sem, 1);
+       smp_wmb(); /* Ensure that bp->intr_sem update is SMP-safe */
 
        mutex_init(&bp->port.phy_mutex);
 
@@ -8268,6 +8374,7 @@ static int bnx2x_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
                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_BCM8727:
                        cmd->port = PORT_FIBRE;
                        break;
 
@@ -9242,9 +9349,17 @@ static int bnx2x_set_tso(struct net_device *dev, u32 data)
        if (data) {
                dev->features |= (NETIF_F_TSO | NETIF_F_TSO_ECN);
                dev->features |= NETIF_F_TSO6;
+#ifdef BCM_VLAN
+               dev->vlan_features |= (NETIF_F_TSO | NETIF_F_TSO_ECN);
+               dev->vlan_features |= NETIF_F_TSO6;
+#endif
        } else {
                dev->features &= ~(NETIF_F_TSO | NETIF_F_TSO_ECN);
                dev->features &= ~NETIF_F_TSO6;
+#ifdef BCM_VLAN
+               dev->vlan_features &= ~(NETIF_F_TSO | NETIF_F_TSO_ECN);
+               dev->vlan_features &= ~NETIF_F_TSO6;
+#endif
        }
 
        return 0;
@@ -9691,8 +9806,15 @@ static void bnx2x_self_test(struct net_device *dev,
                etest->flags &= ~ETH_TEST_FL_OFFLINE;
 
        if (etest->flags & ETH_TEST_FL_OFFLINE) {
+               int port = BP_PORT(bp);
+               u32 val;
                u8 link_up;
 
+               /* save current value of input enable for TX port IF */
+               val = REG_RD(bp, NIG_REG_EGRESS_UMP0_IN_EN + port*4);
+               /* disable input for TX port IF */
+               REG_WR(bp, NIG_REG_EGRESS_UMP0_IN_EN + port*4, 0);
+
                link_up = bp->link_vars.link_up;
                bnx2x_nic_unload(bp, UNLOAD_NORMAL);
                bnx2x_nic_load(bp, LOAD_DIAG);
@@ -9712,6 +9834,10 @@ static void bnx2x_self_test(struct net_device *dev,
                        etest->flags |= ETH_TEST_FL_FAILED;
 
                bnx2x_nic_unload(bp, UNLOAD_NORMAL);
+
+               /* restore input for TX port IF */
+               REG_WR(bp, NIG_REG_EGRESS_UMP0_IN_EN + port*4, val);
+
                bnx2x_nic_load(bp, LOAD_NORMAL);
                /* wait until link state is restored */
                bnx2x_wait_for_link(bp, link_up);
@@ -11064,12 +11190,19 @@ static int __devinit bnx2x_init_dev(struct pci_dev *pdev,
        dev->features |= NETIF_F_HW_CSUM;
        if (bp->flags & USING_DAC_FLAG)
                dev->features |= NETIF_F_HIGHDMA;
+       dev->features |= (NETIF_F_TSO | NETIF_F_TSO_ECN);
+       dev->features |= NETIF_F_TSO6;
 #ifdef BCM_VLAN
        dev->features |= (NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX);
        bp->flags |= (HW_VLAN_RX_FLAG | HW_VLAN_TX_FLAG);
+
+       dev->vlan_features |= NETIF_F_SG;
+       dev->vlan_features |= NETIF_F_HW_CSUM;
+       if (bp->flags & USING_DAC_FLAG)
+               dev->vlan_features |= NETIF_F_HIGHDMA;
+       dev->vlan_features |= (NETIF_F_TSO | NETIF_F_TSO_ECN);
+       dev->vlan_features |= NETIF_F_TSO6;
 #endif
-       dev->features |= (NETIF_F_TSO | NETIF_F_TSO_ECN);
-       dev->features |= NETIF_F_TSO6;
 
        return 0;
 
index b8ce6fc..d771168 100644 (file)
 #define NIG_REG_EGRESS_PBF0_IN_EN                               0x100cc
 /* [RW 1] Input enable for TX PBF user packet port1 IF */
 #define NIG_REG_EGRESS_PBF1_IN_EN                               0x100d0
+/* [RW 1] Input enable for TX UMP management packet port0 IF */
+#define NIG_REG_EGRESS_UMP0_IN_EN                               0x100d4
 /* [RW 1] Input enable for RX_EMAC0 IF */
 #define NIG_REG_EMAC0_IN_EN                                     0x100a4
 /* [RW 1] output enable for TX EMAC pause port 0 IF */
@@ -5843,25 +5845,33 @@ 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_PLL_CTRL          0xca1e
 #define MDIO_PMA_REG_MISC_CTRL0        0xca23
 #define MDIO_PMA_REG_LRM_MODE          0xca3f
 #define MDIO_PMA_REG_CDR_BANDWIDTH     0xca46
 #define MDIO_PMA_REG_MISC_CTRL1        0xca85
 
-#define MDIO_PMA_REG_8726_TWO_WIRE_CTRL        0x8000
-#define MDIO_PMA_REG_8726_TWO_WIRE_CTRL_STATUS_MASK    0x000c
-#define MDIO_PMA_REG_8726_TWO_WIRE_STATUS_IDLE         0x0000
-#define MDIO_PMA_REG_8726_TWO_WIRE_STATUS_COMPLETE     0x0004
-#define MDIO_PMA_REG_8726_TWO_WIRE_STATUS_IN_PROGRESS  0x0008
-#define MDIO_PMA_REG_8726_TWO_WIRE_STATUS_FAILED       0x000c
-#define MDIO_PMA_REG_8726_TWO_WIRE_BYTE_CNT    0x8002
-#define MDIO_PMA_REG_8726_TWO_WIRE_MEM_ADDR    0x8003
+#define MDIO_PMA_REG_SFP_TWO_WIRE_CTRL         0x8000
+#define MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK     0x000c
+#define MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_IDLE          0x0000
+#define MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE      0x0004
+#define MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_IN_PROGRESS   0x0008
+#define MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_FAILED        0x000c
+#define MDIO_PMA_REG_SFP_TWO_WIRE_BYTE_CNT     0x8002
+#define MDIO_PMA_REG_SFP_TWO_WIRE_MEM_ADDR     0x8003
 #define MDIO_PMA_REG_8726_TWO_WIRE_DATA_BUF    0xc820
 #define MDIO_PMA_REG_8726_TWO_WIRE_DATA_MASK 0xff
 #define MDIO_PMA_REG_8726_TX_CTRL1             0xca01
 #define MDIO_PMA_REG_8726_TX_CTRL2             0xca05
 
+#define MDIO_PMA_REG_8727_TWO_WIRE_SLAVE_ADDR  0x8005
+#define MDIO_PMA_REG_8727_TWO_WIRE_DATA_BUF    0x8007
+#define MDIO_PMA_REG_8727_TWO_WIRE_DATA_MASK 0xff
+#define MDIO_PMA_REG_8727_MISC_CTRL            0x8309
+#define MDIO_PMA_REG_8727_TX_CTRL1             0xca02
+#define MDIO_PMA_REG_8727_TX_CTRL2             0xca05
+#define MDIO_PMA_REG_8727_PCS_OPT_CTRL         0xc808
+#define MDIO_PMA_REG_8727_GPIO_CTRL            0xc80e
 
 #define MDIO_PMA_REG_8073_CHIP_REV                     0xc801
 #define MDIO_PMA_REG_8073_SPEED_LINK_STATUS            0xc820
index d4b5708..be799d2 100644 (file)
@@ -1109,7 +1109,8 @@ static void ad_rx_machine(struct lacpdu *lacpdu, struct port *port)
                        //mux machine in case of EXPIRED even if LINK_DOWN didn't arrive for the port.
                        port->partner_oper.port_state &= ~AD_STATE_SYNCHRONIZATION;
                        port->sm_vars &= ~AD_PORT_MATCHED;
-                       port->partner_oper.port_state |= AD_SHORT_TIMEOUT;
+                       port->partner_oper.port_state |=
+                               AD_STATE_LACP_ACTIVITY;
                        port->sm_rx_timer_counter = __ad_timer_to_ticks(AD_CURRENT_WHILE_TIMER, (u16)(AD_SHORT_TIMEOUT));
                        port->actor_oper_port_state |= AD_STATE_EXPIRED;
                        break;
@@ -2431,7 +2432,7 @@ out:
                dev_kfree_skb(skb);
        }
        read_unlock(&bond->lock);
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 int bond_3ad_lacpdu_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type* ptype, struct net_device *orig_dev)
index 46d312b..bf45d20 100644 (file)
@@ -1413,7 +1413,7 @@ out:
        }
        read_unlock(&bond->curr_slave_lock);
        read_unlock(&bond->lock);
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 void bond_alb_monitor(struct work_struct *work)
index aa1be1f..3bf0cc6 100644 (file)
@@ -4285,7 +4285,7 @@ out:
                dev_kfree_skb(skb);
        }
        read_unlock(&bond->lock);
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 
@@ -4316,7 +4316,7 @@ out:
 
        read_unlock(&bond->curr_slave_lock);
        read_unlock(&bond->lock);
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 /*
@@ -4362,7 +4362,7 @@ out:
                dev_kfree_skb(skb);
        }
        read_unlock(&bond->lock);
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 /*
@@ -4422,7 +4422,7 @@ out:
 
        /* frame sent to all suitable interfaces */
        read_unlock(&bond->lock);
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 /*------------------------- Device initialization ---------------------------*/
index 33821a8..30ae55d 100644 (file)
@@ -61,11 +61,12 @@ config CAN_SJA1000_OF_PLATFORM
          you may want to enable this option.
 
 config CAN_EMS_PCI
-       tristate "EMS CPC-PCI and CPC-PCIe Card"
+       tristate "EMS CPC-PCI, CPC-PCIe and CPC-104P Card"
        depends on PCI && CAN_SJA1000
        ---help---
-         This driver is for the one or two channel CPC-PCI and CPC-PCIe
-         cards from EMS Dr. Thomas Wuensche (http://www.ems-wuensche.de).
+         This driver is for the one, two or four channel CPC-PCI,
+         CPC-PCIe and CPC-104P cards from EMS Dr. Thomas Wuensche
+         (http://www.ems-wuensche.de).
 
 config CAN_KVASER_PCI
        tristate "Kvaser PCIcanx and Kvaser PCIcan PCI Cards"
index 121b641..7d84b8a 100644 (file)
 #define DRV_NAME  "ems_pci"
 
 MODULE_AUTHOR("Sebastian Haas <haas@ems-wuenche.com>");
-MODULE_DESCRIPTION("Socket-CAN driver for EMS CPC-PCI/PCIe CAN cards");
-MODULE_SUPPORTED_DEVICE("EMS CPC-PCI/PCIe CAN card");
+MODULE_DESCRIPTION("Socket-CAN driver for EMS CPC-PCI/PCIe/104P CAN cards");
+MODULE_SUPPORTED_DEVICE("EMS CPC-PCI/PCIe/104P CAN card");
 MODULE_LICENSE("GPL v2");
 
-#define EMS_PCI_MAX_CHAN 2
+#define EMS_PCI_V1_MAX_CHAN 2
+#define EMS_PCI_V2_MAX_CHAN 4
+#define EMS_PCI_MAX_CHAN    EMS_PCI_V2_MAX_CHAN
 
 struct ems_pci_card {
+       int version;
        int channels;
 
        struct pci_dev *pci_dev;
@@ -63,12 +66,22 @@ struct ems_pci_card {
 #define PITA2_MISC_CONFIG   0x04000000 /* Multiplexed parallel interface */
 
 /*
+ * Register definitions for the PLX 9030
+ */
+#define PLX_ICSR            0x4c   /* Interrupt Control/Status register */
+#define PLX_ICSR_LINTI1_ENA 0x0001 /* LINTi1 Enable */
+#define PLX_ICSR_PCIINT_ENA 0x0040 /* PCI Interrupt Enable */
+#define PLX_ICSR_LINTI1_CLR 0x0400 /* Local Edge Triggerable Interrupt Clear */
+#define PLX_ICSR_ENA_CLR    (PLX_ICSR_LINTI1_ENA | PLX_ICSR_PCIINT_ENA | \
+                            PLX_ICSR_LINTI1_CLR)
+
+/*
  * The board configuration is probably following:
  * RX1 is connected to ground.
  * TX1 is not connected.
  * CLKO is not connected.
  * Setting the OCR register to 0xDA is a good idea.
- * This means  normal output mode , push-pull and the correct polarity.
+ * This means normal output mode, push-pull and the correct polarity.
  */
 #define EMS_PCI_OCR         (OCR_TX0_PUSHPULL | OCR_TX1_PUSHPULL)
 
@@ -79,17 +92,21 @@ struct ems_pci_card {
  * is driven by the first one CLKOUT output.
  */
 #define EMS_PCI_CDR             (CDR_CBP | CDR_CLKOUT_MASK)
-#define EMS_PCI_MEM_SIZE        4096  /* Size of the remapped io-memory */
+
+#define EMS_PCI_V1_BASE_BAR     1
+#define EMS_PCI_V1_MEM_SIZE     4096
+#define EMS_PCI_V2_BASE_BAR     2
+#define EMS_PCI_V2_MEM_SIZE     128
 #define EMS_PCI_CAN_BASE_OFFSET 0x400 /* offset where the controllers starts */
 #define EMS_PCI_CAN_CTRL_SIZE   0x200 /* memory size for each controller */
 
-#define EMS_PCI_PORT_BYTES  0x4     /* Each register occupies 4 bytes */
-
-#define EMS_PCI_VENDOR_ID   0x110a  /* PCI device and vendor ID */
-#define EMS_PCI_DEVICE_ID   0x2104
-
 static struct pci_device_id ems_pci_tbl[] = {
-       {EMS_PCI_VENDOR_ID, EMS_PCI_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,},
+       /* CPC-PCI v1 */
+       {PCI_VENDOR_ID_SIEMENS, 0x2104, PCI_ANY_ID, PCI_ANY_ID,},
+       /* CPC-PCI v2 */
+       {PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030, PCI_VENDOR_ID_PLX, 0x4000},
+       /* CPC-104P v2 */
+       {PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030, PCI_VENDOR_ID_PLX, 0x4002},
        {0,}
 };
 MODULE_DEVICE_TABLE(pci, ems_pci_tbl);
@@ -97,28 +114,47 @@ MODULE_DEVICE_TABLE(pci, ems_pci_tbl);
 /*
  * Helper to read internal registers from card logic (not CAN)
  */
-static u8 ems_pci_readb(struct ems_pci_card *card, unsigned int port)
+static u8 ems_pci_v1_readb(struct ems_pci_card *card, unsigned int port)
 {
-       return readb(card->base_addr + (port * EMS_PCI_PORT_BYTES));
+       return readb(card->base_addr + (port * 4));
 }
 
-static u8 ems_pci_read_reg(const struct sja1000_priv *priv, int port)
+static u8 ems_pci_v1_read_reg(const struct sja1000_priv *priv, int port)
 {
-       return readb(priv->reg_base + (port * EMS_PCI_PORT_BYTES));
+       return readb(priv->reg_base + (port * 4));
 }
 
-static void ems_pci_write_reg(const struct sja1000_priv *priv, int port, u8 val)
+static void ems_pci_v1_write_reg(const struct sja1000_priv *priv,
+                                int port, u8 val)
 {
-       writeb(val, priv->reg_base + (port * EMS_PCI_PORT_BYTES));
+       writeb(val, priv->reg_base + (port * 4));
 }
 
-static void ems_pci_post_irq(const struct sja1000_priv *priv)
+static void ems_pci_v1_post_irq(const struct sja1000_priv *priv)
 {
        struct ems_pci_card *card = (struct ems_pci_card *)priv->priv;
 
        /* reset int flag of pita */
-       writel(PITA2_ICR_INT0_EN | PITA2_ICR_INT0, card->conf_addr
-               + PITA2_ICR);
+       writel(PITA2_ICR_INT0_EN | PITA2_ICR_INT0,
+              card->conf_addr + PITA2_ICR);
+}
+
+static u8 ems_pci_v2_read_reg(const struct sja1000_priv *priv, int port)
+{
+       return readb(priv->reg_base + port);
+}
+
+static void ems_pci_v2_write_reg(const struct sja1000_priv *priv,
+                                int port, u8 val)
+{
+       writeb(val, priv->reg_base + port);
+}
+
+static void ems_pci_v2_post_irq(const struct sja1000_priv *priv)
+{
+       struct ems_pci_card *card = (struct ems_pci_card *)priv->priv;
+
+       writel(PLX_ICSR_ENA_CLR, card->conf_addr + PLX_ICSR);
 }
 
 /*
@@ -130,12 +166,12 @@ static inline int ems_pci_check_chan(const struct sja1000_priv *priv)
        unsigned char res;
 
        /* Make sure SJA1000 is in reset mode */
-       ems_pci_write_reg(priv, REG_MOD, 1);
+       priv->write_reg(priv, REG_MOD, 1);
 
-       ems_pci_write_reg(priv, REG_CDR, CDR_PELICAN);
+       priv->write_reg(priv, REG_CDR, CDR_PELICAN);
 
        /* read reset-values */
-       res = ems_pci_read_reg(priv, REG_CDR);
+       res = priv->read_reg(priv, REG_CDR);
 
        if (res == CDR_PELICAN)
                return 1;
@@ -188,6 +224,7 @@ static int __devinit ems_pci_add_card(struct pci_dev *pdev,
        struct sja1000_priv *priv;
        struct net_device *dev;
        struct ems_pci_card *card;
+       int max_chan, mem_size, base_bar;
        int err, i;
 
        /* Enabling PCI device */
@@ -210,37 +247,52 @@ static int __devinit ems_pci_add_card(struct pci_dev *pdev,
 
        card->channels = 0;
 
-       /* Remap PITA configuration space, and controller memory area */
-       card->conf_addr = pci_iomap(pdev, 0, EMS_PCI_MEM_SIZE);
+       if (pdev->vendor == PCI_VENDOR_ID_PLX) {
+               card->version = 2; /* CPC-PCI v2 */
+               max_chan = EMS_PCI_V2_MAX_CHAN;
+               base_bar = EMS_PCI_V2_BASE_BAR;
+               mem_size = EMS_PCI_V2_MEM_SIZE;
+       } else {
+               card->version = 1; /* CPC-PCI v1 */
+               max_chan = EMS_PCI_V1_MAX_CHAN;
+               base_bar = EMS_PCI_V1_BASE_BAR;
+               mem_size = EMS_PCI_V1_MEM_SIZE;
+       }
+
+       /* Remap configuration space and controller memory area */
+       card->conf_addr = pci_iomap(pdev, 0, mem_size);
        if (card->conf_addr == NULL) {
                err = -ENOMEM;
                goto failure_cleanup;
        }
 
-       card->base_addr = pci_iomap(pdev, 1, EMS_PCI_MEM_SIZE);
+       card->base_addr = pci_iomap(pdev, base_bar, mem_size);
        if (card->base_addr == NULL) {
                err = -ENOMEM;
                goto failure_cleanup;
        }
 
-       /* Configure PITA-2 parallel interface (enable MUX) */
-       writel(PITA2_MISC_CONFIG, card->conf_addr + PITA2_MISC);
-
-       /* Check for unique EMS CAN signature */
-       if (ems_pci_readb(card, 0) != 0x55 ||
-           ems_pci_readb(card, 1) != 0xAA ||
-           ems_pci_readb(card, 2) != 0x01 ||
-           ems_pci_readb(card, 3) != 0xCB ||
-           ems_pci_readb(card, 4) != 0x11) {
-               dev_err(&pdev->dev, "Not EMS Dr. Thomas Wuensche interface\n");
-               err = -ENODEV;
-               goto failure_cleanup;
+       if (card->version == 1) {
+               /* Configure PITA-2 parallel interface (enable MUX) */
+               writel(PITA2_MISC_CONFIG, card->conf_addr + PITA2_MISC);
+
+               /* Check for unique EMS CAN signature */
+               if (ems_pci_v1_readb(card, 0) != 0x55 ||
+                   ems_pci_v1_readb(card, 1) != 0xAA ||
+                   ems_pci_v1_readb(card, 2) != 0x01 ||
+                   ems_pci_v1_readb(card, 3) != 0xCB ||
+                   ems_pci_v1_readb(card, 4) != 0x11) {
+                       dev_err(&pdev->dev,
+                               "Not EMS Dr. Thomas Wuensche interface\n");
+                       err = -ENODEV;
+                       goto failure_cleanup;
+               }
        }
 
        ems_pci_card_reset(card);
 
        /* Detect available channels */
-       for (i = 0; i < EMS_PCI_MAX_CHAN; i++) {
+       for (i = 0; i < max_chan; i++) {
                dev = alloc_sja1000dev(0);
                if (dev == NULL) {
                        err = -ENOMEM;
@@ -255,20 +307,32 @@ static int __devinit ems_pci_add_card(struct pci_dev *pdev,
                dev->irq = pdev->irq;
                priv->reg_base = card->base_addr + EMS_PCI_CAN_BASE_OFFSET
                                        + (i * EMS_PCI_CAN_CTRL_SIZE);
+               if (card->version == 1) {
+                       priv->read_reg  = ems_pci_v1_read_reg;
+                       priv->write_reg = ems_pci_v1_write_reg;
+                       priv->post_irq  = ems_pci_v1_post_irq;
+               } else {
+                       priv->read_reg  = ems_pci_v2_read_reg;
+                       priv->write_reg = ems_pci_v2_write_reg;
+                       priv->post_irq  = ems_pci_v2_post_irq;
+               }
 
                /* Check if channel is present */
                if (ems_pci_check_chan(priv)) {
-                       priv->read_reg  = ems_pci_read_reg;
-                       priv->write_reg = ems_pci_write_reg;
-                       priv->post_irq  = ems_pci_post_irq;
                        priv->can.clock.freq = EMS_PCI_CAN_CLOCK;
                        priv->ocr = EMS_PCI_OCR;
                        priv->cdr = EMS_PCI_CDR;
 
                        SET_NETDEV_DEV(dev, &pdev->dev);
 
-                       /* Enable interrupts from card */
-                       writel(PITA2_ICR_INT0_EN, card->conf_addr + PITA2_ICR);
+                       if (card->version == 1)
+                               /* reset int flag of pita */
+                               writel(PITA2_ICR_INT0_EN | PITA2_ICR_INT0,
+                                      card->conf_addr + PITA2_ICR);
+                       else
+                               /* enable IRQ in PLX 9030 */
+                               writel(PLX_ICSR_ENA_CLR,
+                                      card->conf_addr + PLX_ICSR);
 
                        /* Register SJA1000 device */
                        err = register_sja1000dev(dev);
index 08ebee7..b3004de 100644 (file)
@@ -282,7 +282,7 @@ static int sja1000_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
        priv->write_reg(priv, REG_CMR, CMD_TR);
 
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 static void sja1000_rx(struct net_device *dev)
index eb06667..299a33b 100644 (file)
@@ -2928,7 +2928,7 @@ static int cas_start_xmit(struct sk_buff *skb, struct net_device *dev)
        static int ring;
 
        if (skb_padto(skb, cp->min_frame_size))
-               return 0;
+               return NETDEV_TX_OK;
 
        /* XXX: we need some higher-level QoS hooks to steer packets to
         *      individual queues.
@@ -2936,7 +2936,7 @@ static int cas_start_xmit(struct sk_buff *skb, struct net_device *dev)
        if (cas_xmit_tx_ringN(cp, ring++ & N_TX_RINGS_MASK, skb))
                return NETDEV_TX_BUSY;
        dev->trans_start = jiffies;
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 static void cas_init_tx_dma(struct cas *cp)
index 7a18dc7..15c0195 100644 (file)
@@ -1108,7 +1108,7 @@ e100_send_packet(struct sk_buff *skb, struct net_device *dev)
 
        spin_unlock_irqrestore(&np->lock, flags);
 
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 /*
index 55445f9..ecf88ab 100644 (file)
@@ -1367,7 +1367,7 @@ net_open(struct net_device *dev)
                        spin_lock_irqsave(&lp->lock, flags);
                        disable_dma(dev->dma);
                        clear_dma_ff(dev->dma);
-                       set_dma_mode(dev->dma, 0x14); /* auto_init as well */
+                       set_dma_mode(dev->dma, DMA_RX_MODE); /* auto_init as well */
                        set_dma_addr(dev->dma, isa_virt_to_bus(lp->dma_buff));
                        set_dma_count(dev->dma, lp->dmasize*1024);
                        enable_dma(dev->dma);
@@ -1572,7 +1572,7 @@ static int net_send_packet(struct sk_buff *skb, struct net_device *dev)
         * to restart the netdevice layer
         */
 
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 /* The typical workload of the driver:
index 1694fad..74723f2 100644 (file)
@@ -276,6 +276,14 @@ static inline struct port_info *adap2pinfo(struct adapter *adap, int idx)
        return netdev_priv(adap->port[idx]);
 }
 
+static inline int phy2portid(struct cphy *phy)
+{
+       struct adapter *adap = phy->adapter;
+       struct port_info *port0 = adap2pinfo(adap, 0);
+
+       return &port0->phy == phy ? 0 : 1;
+}
+
 #define OFFLOAD_DEVMAP_BIT 15
 
 #define tdev2adap(d) container_of(d, struct adapter, tdev)
@@ -312,4 +320,6 @@ int t3_get_desc(const struct sge_qset *qs, unsigned int qnum, unsigned int idx,
                unsigned char *data);
 irqreturn_t t3_sge_intr_msix(int irq, void *cookie);
 
+int t3_get_edc_fw(struct cphy *phy, int edc_idx, int size);
+
 #endif                         /* __T3_ADAPTER_H__ */
index 9fe008e..5248f9e 100644 (file)
@@ -224,12 +224,6 @@ static int ael1006_reset(struct cphy *phy, int wait)
        return t3_phy_reset(phy, MDIO_MMD_PMAPMD, wait);
 }
 
-static int ael1006_power_down(struct cphy *phy, int enable)
-{
-       return mdio_set_flag(&phy->mdio, phy->mdio.prtad, MDIO_MMD_PMAPMD,
-                            MDIO_CTRL1, MDIO_CTRL1_LPOWER, enable);
-}
-
 static struct cphy_ops ael1006_ops = {
        .reset = ael1006_reset,
        .intr_enable = t3_phy_lasi_intr_enable,
@@ -237,7 +231,7 @@ static struct cphy_ops ael1006_ops = {
        .intr_clear = t3_phy_lasi_intr_clear,
        .intr_handler = t3_phy_lasi_intr_handler,
        .get_link_status = get_link_status_r,
-       .power_down = ael1006_power_down,
+       .power_down = ael1002_power_down,
        .mmds = MDIO_DEVS_PMAPMD | MDIO_DEVS_PCS | MDIO_DEVS_PHYXS,
 };
 
@@ -304,279 +298,7 @@ static int ael2005_setup_sr_edc(struct cphy *phy)
                { MDIO_MMD_PMAPMD, 0xc04a, 0xffff, 0x5200 },
                { 0, 0, 0, 0 }
        };
-       static u16 sr_edc[] = {
-               0xcc00, 0x2ff4,
-               0xcc01, 0x3cd4,
-               0xcc02, 0x2015,
-               0xcc03, 0x3105,
-               0xcc04, 0x6524,
-               0xcc05, 0x27ff,
-               0xcc06, 0x300f,
-               0xcc07, 0x2c8b,
-               0xcc08, 0x300b,
-               0xcc09, 0x4009,
-               0xcc0a, 0x400e,
-               0xcc0b, 0x2f72,
-               0xcc0c, 0x3002,
-               0xcc0d, 0x1002,
-               0xcc0e, 0x2172,
-               0xcc0f, 0x3012,
-               0xcc10, 0x1002,
-               0xcc11, 0x25d2,
-               0xcc12, 0x3012,
-               0xcc13, 0x1002,
-               0xcc14, 0xd01e,
-               0xcc15, 0x27d2,
-               0xcc16, 0x3012,
-               0xcc17, 0x1002,
-               0xcc18, 0x2004,
-               0xcc19, 0x3c84,
-               0xcc1a, 0x6436,
-               0xcc1b, 0x2007,
-               0xcc1c, 0x3f87,
-               0xcc1d, 0x8676,
-               0xcc1e, 0x40b7,
-               0xcc1f, 0xa746,
-               0xcc20, 0x4047,
-               0xcc21, 0x5673,
-               0xcc22, 0x2982,
-               0xcc23, 0x3002,
-               0xcc24, 0x13d2,
-               0xcc25, 0x8bbd,
-               0xcc26, 0x2862,
-               0xcc27, 0x3012,
-               0xcc28, 0x1002,
-               0xcc29, 0x2092,
-               0xcc2a, 0x3012,
-               0xcc2b, 0x1002,
-               0xcc2c, 0x5cc3,
-               0xcc2d, 0x314,
-               0xcc2e, 0x2942,
-               0xcc2f, 0x3002,
-               0xcc30, 0x1002,
-               0xcc31, 0xd019,
-               0xcc32, 0x2032,
-               0xcc33, 0x3012,
-               0xcc34, 0x1002,
-               0xcc35, 0x2a04,
-               0xcc36, 0x3c74,
-               0xcc37, 0x6435,
-               0xcc38, 0x2fa4,
-               0xcc39, 0x3cd4,
-               0xcc3a, 0x6624,
-               0xcc3b, 0x5563,
-               0xcc3c, 0x2d42,
-               0xcc3d, 0x3002,
-               0xcc3e, 0x13d2,
-               0xcc3f, 0x464d,
-               0xcc40, 0x2862,
-               0xcc41, 0x3012,
-               0xcc42, 0x1002,
-               0xcc43, 0x2032,
-               0xcc44, 0x3012,
-               0xcc45, 0x1002,
-               0xcc46, 0x2fb4,
-               0xcc47, 0x3cd4,
-               0xcc48, 0x6624,
-               0xcc49, 0x5563,
-               0xcc4a, 0x2d42,
-               0xcc4b, 0x3002,
-               0xcc4c, 0x13d2,
-               0xcc4d, 0x2ed2,
-               0xcc4e, 0x3002,
-               0xcc4f, 0x1002,
-               0xcc50, 0x2fd2,
-               0xcc51, 0x3002,
-               0xcc52, 0x1002,
-               0xcc53, 0x004,
-               0xcc54, 0x2942,
-               0xcc55, 0x3002,
-               0xcc56, 0x1002,
-               0xcc57, 0x2092,
-               0xcc58, 0x3012,
-               0xcc59, 0x1002,
-               0xcc5a, 0x5cc3,
-               0xcc5b, 0x317,
-               0xcc5c, 0x2f72,
-               0xcc5d, 0x3002,
-               0xcc5e, 0x1002,
-               0xcc5f, 0x2942,
-               0xcc60, 0x3002,
-               0xcc61, 0x1002,
-               0xcc62, 0x22cd,
-               0xcc63, 0x301d,
-               0xcc64, 0x2862,
-               0xcc65, 0x3012,
-               0xcc66, 0x1002,
-               0xcc67, 0x2ed2,
-               0xcc68, 0x3002,
-               0xcc69, 0x1002,
-               0xcc6a, 0x2d72,
-               0xcc6b, 0x3002,
-               0xcc6c, 0x1002,
-               0xcc6d, 0x628f,
-               0xcc6e, 0x2112,
-               0xcc6f, 0x3012,
-               0xcc70, 0x1002,
-               0xcc71, 0x5aa3,
-               0xcc72, 0x2dc2,
-               0xcc73, 0x3002,
-               0xcc74, 0x1312,
-               0xcc75, 0x6f72,
-               0xcc76, 0x1002,
-               0xcc77, 0x2807,
-               0xcc78, 0x31a7,
-               0xcc79, 0x20c4,
-               0xcc7a, 0x3c24,
-               0xcc7b, 0x6724,
-               0xcc7c, 0x1002,
-               0xcc7d, 0x2807,
-               0xcc7e, 0x3187,
-               0xcc7f, 0x20c4,
-               0xcc80, 0x3c24,
-               0xcc81, 0x6724,
-               0xcc82, 0x1002,
-               0xcc83, 0x2514,
-               0xcc84, 0x3c64,
-               0xcc85, 0x6436,
-               0xcc86, 0xdff4,
-               0xcc87, 0x6436,
-               0xcc88, 0x1002,
-               0xcc89, 0x40a4,
-               0xcc8a, 0x643c,
-               0xcc8b, 0x4016,
-               0xcc8c, 0x8c6c,
-               0xcc8d, 0x2b24,
-               0xcc8e, 0x3c24,
-               0xcc8f, 0x6435,
-               0xcc90, 0x1002,
-               0xcc91, 0x2b24,
-               0xcc92, 0x3c24,
-               0xcc93, 0x643a,
-               0xcc94, 0x4025,
-               0xcc95, 0x8a5a,
-               0xcc96, 0x1002,
-               0xcc97, 0x2731,
-               0xcc98, 0x3011,
-               0xcc99, 0x1001,
-               0xcc9a, 0xc7a0,
-               0xcc9b, 0x100,
-               0xcc9c, 0xc502,
-               0xcc9d, 0x53ac,
-               0xcc9e, 0xc503,
-               0xcc9f, 0xd5d5,
-               0xcca0, 0xc600,
-               0xcca1, 0x2a6d,
-               0xcca2, 0xc601,
-               0xcca3, 0x2a4c,
-               0xcca4, 0xc602,
-               0xcca5, 0x111,
-               0xcca6, 0xc60c,
-               0xcca7, 0x5900,
-               0xcca8, 0xc710,
-               0xcca9, 0x700,
-               0xccaa, 0xc718,
-               0xccab, 0x700,
-               0xccac, 0xc720,
-               0xccad, 0x4700,
-               0xccae, 0xc801,
-               0xccaf, 0x7f50,
-               0xccb0, 0xc802,
-               0xccb1, 0x7760,
-               0xccb2, 0xc803,
-               0xccb3, 0x7fce,
-               0xccb4, 0xc804,
-               0xccb5, 0x5700,
-               0xccb6, 0xc805,
-               0xccb7, 0x5f11,
-               0xccb8, 0xc806,
-               0xccb9, 0x4751,
-               0xccba, 0xc807,
-               0xccbb, 0x57e1,
-               0xccbc, 0xc808,
-               0xccbd, 0x2700,
-               0xccbe, 0xc809,
-               0xccbf, 0x000,
-               0xccc0, 0xc821,
-               0xccc1, 0x002,
-               0xccc2, 0xc822,
-               0xccc3, 0x014,
-               0xccc4, 0xc832,
-               0xccc5, 0x1186,
-               0xccc6, 0xc847,
-               0xccc7, 0x1e02,
-               0xccc8, 0xc013,
-               0xccc9, 0xf341,
-               0xccca, 0xc01a,
-               0xcccb, 0x446,
-               0xcccc, 0xc024,
-               0xcccd, 0x1000,
-               0xccce, 0xc025,
-               0xcccf, 0xa00,
-               0xccd0, 0xc026,
-               0xccd1, 0xc0c,
-               0xccd2, 0xc027,
-               0xccd3, 0xc0c,
-               0xccd4, 0xc029,
-               0xccd5, 0x0a0,
-               0xccd6, 0xc030,
-               0xccd7, 0xa00,
-               0xccd8, 0xc03c,
-               0xccd9, 0x01c,
-               0xccda, 0xc005,
-               0xccdb, 0x7a06,
-               0xccdc, 0x000,
-               0xccdd, 0x2731,
-               0xccde, 0x3011,
-               0xccdf, 0x1001,
-               0xcce0, 0xc620,
-               0xcce1, 0x000,
-               0xcce2, 0xc621,
-               0xcce3, 0x03f,
-               0xcce4, 0xc622,
-               0xcce5, 0x000,
-               0xcce6, 0xc623,
-               0xcce7, 0x000,
-               0xcce8, 0xc624,
-               0xcce9, 0x000,
-               0xccea, 0xc625,
-               0xcceb, 0x000,
-               0xccec, 0xc627,
-               0xcced, 0x000,
-               0xccee, 0xc628,
-               0xccef, 0x000,
-               0xccf0, 0xc62c,
-               0xccf1, 0x000,
-               0xccf2, 0x000,
-               0xccf3, 0x2806,
-               0xccf4, 0x3cb6,
-               0xccf5, 0xc161,
-               0xccf6, 0x6134,
-               0xccf7, 0x6135,
-               0xccf8, 0x5443,
-               0xccf9, 0x303,
-               0xccfa, 0x6524,
-               0xccfb, 0x00b,
-               0xccfc, 0x1002,
-               0xccfd, 0x2104,
-               0xccfe, 0x3c24,
-               0xccff, 0x2105,
-               0xcd00, 0x3805,
-               0xcd01, 0x6524,
-               0xcd02, 0xdff4,
-               0xcd03, 0x4005,
-               0xcd04, 0x6524,
-               0xcd05, 0x1002,
-               0xcd06, 0x5dd3,
-               0xcd07, 0x306,
-               0xcd08, 0x2ff7,
-               0xcd09, 0x38f7,
-               0xcd0a, 0x60b7,
-               0xcd0b, 0xdffd,
-               0xcd0c, 0x00a,
-               0xcd0d, 0x1002,
-               0xcd0e, 0
-       };
+
        int i, err;
 
        err = set_phy_regs(phy, regs);
@@ -585,9 +307,16 @@ static int ael2005_setup_sr_edc(struct cphy *phy)
 
        msleep(50);
 
-       for (i = 0; i < ARRAY_SIZE(sr_edc) && !err; i += 2)
-               err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, sr_edc[i],
-                                   sr_edc[i + 1]);
+       if (phy->priv != edc_sr)
+               err = t3_get_edc_fw(phy, EDC_OPT_AEL2005,
+                                   EDC_OPT_AEL2005_SIZE);
+       if (err)
+               return err;
+
+       for (i = 0; i <  EDC_OPT_AEL2005_SIZE / sizeof(u16) && !err; i += 2)
+               err = t3_mdio_write(phy, MDIO_MMD_PMAPMD,
+                                   phy->phy_cache[i],
+                                   phy->phy_cache[i + 1]);
        if (!err)
                phy->priv = edc_sr;
        return err;
@@ -604,374 +333,6 @@ static int ael2005_setup_twinax_edc(struct cphy *phy, int modtype)
                { MDIO_MMD_PMAPMD, 0xc015, 0xffff, 0xa000 },
                { 0, 0, 0, 0 }
        };
-       static u16 twinax_edc[] = {
-               0xcc00, 0x4009,
-               0xcc01, 0x27ff,
-               0xcc02, 0x300f,
-               0xcc03, 0x40aa,
-               0xcc04, 0x401c,
-               0xcc05, 0x401e,
-               0xcc06, 0x2ff4,
-               0xcc07, 0x3cd4,
-               0xcc08, 0x2035,
-               0xcc09, 0x3145,
-               0xcc0a, 0x6524,
-               0xcc0b, 0x26a2,
-               0xcc0c, 0x3012,
-               0xcc0d, 0x1002,
-               0xcc0e, 0x29c2,
-               0xcc0f, 0x3002,
-               0xcc10, 0x1002,
-               0xcc11, 0x2072,
-               0xcc12, 0x3012,
-               0xcc13, 0x1002,
-               0xcc14, 0x22cd,
-               0xcc15, 0x301d,
-               0xcc16, 0x2e52,
-               0xcc17, 0x3012,
-               0xcc18, 0x1002,
-               0xcc19, 0x28e2,
-               0xcc1a, 0x3002,
-               0xcc1b, 0x1002,
-               0xcc1c, 0x628f,
-               0xcc1d, 0x2ac2,
-               0xcc1e, 0x3012,
-               0xcc1f, 0x1002,
-               0xcc20, 0x5553,
-               0xcc21, 0x2ae2,
-               0xcc22, 0x3002,
-               0xcc23, 0x1302,
-               0xcc24, 0x401e,
-               0xcc25, 0x2be2,
-               0xcc26, 0x3012,
-               0xcc27, 0x1002,
-               0xcc28, 0x2da2,
-               0xcc29, 0x3012,
-               0xcc2a, 0x1002,
-               0xcc2b, 0x2ba2,
-               0xcc2c, 0x3002,
-               0xcc2d, 0x1002,
-               0xcc2e, 0x5ee3,
-               0xcc2f, 0x305,
-               0xcc30, 0x400e,
-               0xcc31, 0x2bc2,
-               0xcc32, 0x3002,
-               0xcc33, 0x1002,
-               0xcc34, 0x2b82,
-               0xcc35, 0x3012,
-               0xcc36, 0x1002,
-               0xcc37, 0x5663,
-               0xcc38, 0x302,
-               0xcc39, 0x401e,
-               0xcc3a, 0x6f72,
-               0xcc3b, 0x1002,
-               0xcc3c, 0x628f,
-               0xcc3d, 0x2be2,
-               0xcc3e, 0x3012,
-               0xcc3f, 0x1002,
-               0xcc40, 0x22cd,
-               0xcc41, 0x301d,
-               0xcc42, 0x2e52,
-               0xcc43, 0x3012,
-               0xcc44, 0x1002,
-               0xcc45, 0x2522,
-               0xcc46, 0x3012,
-               0xcc47, 0x1002,
-               0xcc48, 0x2da2,
-               0xcc49, 0x3012,
-               0xcc4a, 0x1002,
-               0xcc4b, 0x2ca2,
-               0xcc4c, 0x3012,
-               0xcc4d, 0x1002,
-               0xcc4e, 0x2fa4,
-               0xcc4f, 0x3cd4,
-               0xcc50, 0x6624,
-               0xcc51, 0x410b,
-               0xcc52, 0x56b3,
-               0xcc53, 0x3c4,
-               0xcc54, 0x2fb2,
-               0xcc55, 0x3002,
-               0xcc56, 0x1002,
-               0xcc57, 0x220b,
-               0xcc58, 0x303b,
-               0xcc59, 0x56b3,
-               0xcc5a, 0x3c3,
-               0xcc5b, 0x866b,
-               0xcc5c, 0x400c,
-               0xcc5d, 0x23a2,
-               0xcc5e, 0x3012,
-               0xcc5f, 0x1002,
-               0xcc60, 0x2da2,
-               0xcc61, 0x3012,
-               0xcc62, 0x1002,
-               0xcc63, 0x2ca2,
-               0xcc64, 0x3012,
-               0xcc65, 0x1002,
-               0xcc66, 0x2fb4,
-               0xcc67, 0x3cd4,
-               0xcc68, 0x6624,
-               0xcc69, 0x56b3,
-               0xcc6a, 0x3c3,
-               0xcc6b, 0x866b,
-               0xcc6c, 0x401c,
-               0xcc6d, 0x2205,
-               0xcc6e, 0x3035,
-               0xcc6f, 0x5b53,
-               0xcc70, 0x2c52,
-               0xcc71, 0x3002,
-               0xcc72, 0x13c2,
-               0xcc73, 0x5cc3,
-               0xcc74, 0x317,
-               0xcc75, 0x2522,
-               0xcc76, 0x3012,
-               0xcc77, 0x1002,
-               0xcc78, 0x2da2,
-               0xcc79, 0x3012,
-               0xcc7a, 0x1002,
-               0xcc7b, 0x2b82,
-               0xcc7c, 0x3012,
-               0xcc7d, 0x1002,
-               0xcc7e, 0x5663,
-               0xcc7f, 0x303,
-               0xcc80, 0x401e,
-               0xcc81, 0x004,
-               0xcc82, 0x2c42,
-               0xcc83, 0x3012,
-               0xcc84, 0x1002,
-               0xcc85, 0x6f72,
-               0xcc86, 0x1002,
-               0xcc87, 0x628f,
-               0xcc88, 0x2304,
-               0xcc89, 0x3c84,
-               0xcc8a, 0x6436,
-               0xcc8b, 0xdff4,
-               0xcc8c, 0x6436,
-               0xcc8d, 0x2ff5,
-               0xcc8e, 0x3005,
-               0xcc8f, 0x8656,
-               0xcc90, 0xdfba,
-               0xcc91, 0x56a3,
-               0xcc92, 0xd05a,
-               0xcc93, 0x21c2,
-               0xcc94, 0x3012,
-               0xcc95, 0x1392,
-               0xcc96, 0xd05a,
-               0xcc97, 0x56a3,
-               0xcc98, 0xdfba,
-               0xcc99, 0x383,
-               0xcc9a, 0x6f72,
-               0xcc9b, 0x1002,
-               0xcc9c, 0x28c5,
-               0xcc9d, 0x3005,
-               0xcc9e, 0x4178,
-               0xcc9f, 0x5653,
-               0xcca0, 0x384,
-               0xcca1, 0x22b2,
-               0xcca2, 0x3012,
-               0xcca3, 0x1002,
-               0xcca4, 0x2be5,
-               0xcca5, 0x3005,
-               0xcca6, 0x41e8,
-               0xcca7, 0x5653,
-               0xcca8, 0x382,
-               0xcca9, 0x002,
-               0xccaa, 0x4258,
-               0xccab, 0x2474,
-               0xccac, 0x3c84,
-               0xccad, 0x6437,
-               0xccae, 0xdff4,
-               0xccaf, 0x6437,
-               0xccb0, 0x2ff5,
-               0xccb1, 0x3c05,
-               0xccb2, 0x8757,
-               0xccb3, 0xb888,
-               0xccb4, 0x9787,
-               0xccb5, 0xdff4,
-               0xccb6, 0x6724,
-               0xccb7, 0x866a,
-               0xccb8, 0x6f72,
-               0xccb9, 0x1002,
-               0xccba, 0x2d01,
-               0xccbb, 0x3011,
-               0xccbc, 0x1001,
-               0xccbd, 0xc620,
-               0xccbe, 0x14e5,
-               0xccbf, 0xc621,
-               0xccc0, 0xc53d,
-               0xccc1, 0xc622,
-               0xccc2, 0x3cbe,
-               0xccc3, 0xc623,
-               0xccc4, 0x4452,
-               0xccc5, 0xc624,
-               0xccc6, 0xc5c5,
-               0xccc7, 0xc625,
-               0xccc8, 0xe01e,
-               0xccc9, 0xc627,
-               0xccca, 0x000,
-               0xcccb, 0xc628,
-               0xcccc, 0x000,
-               0xcccd, 0xc62b,
-               0xccce, 0x000,
-               0xcccf, 0xc62c,
-               0xccd0, 0x000,
-               0xccd1, 0x000,
-               0xccd2, 0x2d01,
-               0xccd3, 0x3011,
-               0xccd4, 0x1001,
-               0xccd5, 0xc620,
-               0xccd6, 0x000,
-               0xccd7, 0xc621,
-               0xccd8, 0x000,
-               0xccd9, 0xc622,
-               0xccda, 0x0ce,
-               0xccdb, 0xc623,
-               0xccdc, 0x07f,
-               0xccdd, 0xc624,
-               0xccde, 0x032,
-               0xccdf, 0xc625,
-               0xcce0, 0x000,
-               0xcce1, 0xc627,
-               0xcce2, 0x000,
-               0xcce3, 0xc628,
-               0xcce4, 0x000,
-               0xcce5, 0xc62b,
-               0xcce6, 0x000,
-               0xcce7, 0xc62c,
-               0xcce8, 0x000,
-               0xcce9, 0x000,
-               0xccea, 0x2d01,
-               0xcceb, 0x3011,
-               0xccec, 0x1001,
-               0xcced, 0xc502,
-               0xccee, 0x609f,
-               0xccef, 0xc600,
-               0xccf0, 0x2a6e,
-               0xccf1, 0xc601,
-               0xccf2, 0x2a2c,
-               0xccf3, 0xc60c,
-               0xccf4, 0x5400,
-               0xccf5, 0xc710,
-               0xccf6, 0x700,
-               0xccf7, 0xc718,
-               0xccf8, 0x700,
-               0xccf9, 0xc720,
-               0xccfa, 0x4700,
-               0xccfb, 0xc728,
-               0xccfc, 0x700,
-               0xccfd, 0xc729,
-               0xccfe, 0x1207,
-               0xccff, 0xc801,
-               0xcd00, 0x7f50,
-               0xcd01, 0xc802,
-               0xcd02, 0x7760,
-               0xcd03, 0xc803,
-               0xcd04, 0x7fce,
-               0xcd05, 0xc804,
-               0xcd06, 0x520e,
-               0xcd07, 0xc805,
-               0xcd08, 0x5c11,
-               0xcd09, 0xc806,
-               0xcd0a, 0x3c51,
-               0xcd0b, 0xc807,
-               0xcd0c, 0x4061,
-               0xcd0d, 0xc808,
-               0xcd0e, 0x49c1,
-               0xcd0f, 0xc809,
-               0xcd10, 0x3840,
-               0xcd11, 0xc80a,
-               0xcd12, 0x000,
-               0xcd13, 0xc821,
-               0xcd14, 0x002,
-               0xcd15, 0xc822,
-               0xcd16, 0x046,
-               0xcd17, 0xc844,
-               0xcd18, 0x182f,
-               0xcd19, 0xc013,
-               0xcd1a, 0xf341,
-               0xcd1b, 0xc01a,
-               0xcd1c, 0x446,
-               0xcd1d, 0xc024,
-               0xcd1e, 0x1000,
-               0xcd1f, 0xc025,
-               0xcd20, 0xa00,
-               0xcd21, 0xc026,
-               0xcd22, 0xc0c,
-               0xcd23, 0xc027,
-               0xcd24, 0xc0c,
-               0xcd25, 0xc029,
-               0xcd26, 0x0a0,
-               0xcd27, 0xc030,
-               0xcd28, 0xa00,
-               0xcd29, 0xc03c,
-               0xcd2a, 0x01c,
-               0xcd2b, 0x000,
-               0xcd2c, 0x2b84,
-               0xcd2d, 0x3c74,
-               0xcd2e, 0x6435,
-               0xcd2f, 0xdff4,
-               0xcd30, 0x6435,
-               0xcd31, 0x2806,
-               0xcd32, 0x3006,
-               0xcd33, 0x8565,
-               0xcd34, 0x2b24,
-               0xcd35, 0x3c24,
-               0xcd36, 0x6436,
-               0xcd37, 0x1002,
-               0xcd38, 0x2b24,
-               0xcd39, 0x3c24,
-               0xcd3a, 0x6436,
-               0xcd3b, 0x4045,
-               0xcd3c, 0x8656,
-               0xcd3d, 0x1002,
-               0xcd3e, 0x2807,
-               0xcd3f, 0x31a7,
-               0xcd40, 0x20c4,
-               0xcd41, 0x3c24,
-               0xcd42, 0x6724,
-               0xcd43, 0x1002,
-               0xcd44, 0x2807,
-               0xcd45, 0x3187,
-               0xcd46, 0x20c4,
-               0xcd47, 0x3c24,
-               0xcd48, 0x6724,
-               0xcd49, 0x1002,
-               0xcd4a, 0x2514,
-               0xcd4b, 0x3c64,
-               0xcd4c, 0x6436,
-               0xcd4d, 0xdff4,
-               0xcd4e, 0x6436,
-               0xcd4f, 0x1002,
-               0xcd50, 0x2806,
-               0xcd51, 0x3cb6,
-               0xcd52, 0xc161,
-               0xcd53, 0x6134,
-               0xcd54, 0x6135,
-               0xcd55, 0x5443,
-               0xcd56, 0x303,
-               0xcd57, 0x6524,
-               0xcd58, 0x00b,
-               0xcd59, 0x1002,
-               0xcd5a, 0xd019,
-               0xcd5b, 0x2104,
-               0xcd5c, 0x3c24,
-               0xcd5d, 0x2105,
-               0xcd5e, 0x3805,
-               0xcd5f, 0x6524,
-               0xcd60, 0xdff4,
-               0xcd61, 0x4005,
-               0xcd62, 0x6524,
-               0xcd63, 0x2e8d,
-               0xcd64, 0x303d,
-               0xcd65, 0x5dd3,
-               0xcd66, 0x306,
-               0xcd67, 0x2ff7,
-               0xcd68, 0x38f7,
-               0xcd69, 0x60b7,
-               0xcd6a, 0xdffd,
-               0xcd6b, 0x00a,
-               0xcd6c, 0x1002,
-               0xcd6d, 0
-       };
        int i, err;
 
        err = set_phy_regs(phy, regs);
@@ -982,9 +343,16 @@ static int ael2005_setup_twinax_edc(struct cphy *phy, int modtype)
 
        msleep(50);
 
-       for (i = 0; i < ARRAY_SIZE(twinax_edc) && !err; i += 2)
-               err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, twinax_edc[i],
-                                   twinax_edc[i + 1]);
+       if (phy->priv != edc_twinax)
+               err = t3_get_edc_fw(phy, EDC_TWX_AEL2005,
+                                   EDC_TWX_AEL2005_SIZE);
+       if (err)
+               return err;
+
+       for (i = 0; i <  EDC_TWX_AEL2005_SIZE / sizeof(u16) && !err; i += 2)
+               err = t3_mdio_write(phy, MDIO_MMD_PMAPMD,
+                                   phy->phy_cache[i],
+                                   phy->phy_cache[i + 1]);
        if (!err)
                phy->priv = edc_twinax;
        return err;
@@ -1201,405 +569,6 @@ static int ael2020_setup_twinax_edc(struct cphy *phy, int modtype)
                { MDIO_MMD_PMAPMD, 0xd092, 0xffff, 0x0000 },
                { 0, 0, 0, 0 }
        };
-
-       /* TWINAX EDC firmware */
-       static u16 twinax_edc[] = {
-               0xd800, 0x4009,
-               0xd801, 0x2fff,
-               0xd802, 0x300f,
-               0xd803, 0x40aa,
-               0xd804, 0x401c,
-               0xd805, 0x401e,
-               0xd806, 0x2ff4,
-               0xd807, 0x3dc4,
-               0xd808, 0x2035,
-               0xd809, 0x3035,
-               0xd80a, 0x6524,
-               0xd80b, 0x2cb2,
-               0xd80c, 0x3012,
-               0xd80d, 0x1002,
-               0xd80e, 0x26e2,
-               0xd80f, 0x3022,
-               0xd810, 0x1002,
-               0xd811, 0x27d2,
-               0xd812, 0x3022,
-               0xd813, 0x1002,
-               0xd814, 0x2822,
-               0xd815, 0x3012,
-               0xd816, 0x1002,
-               0xd817, 0x2492,
-               0xd818, 0x3022,
-               0xd819, 0x1002,
-               0xd81a, 0x2772,
-               0xd81b, 0x3012,
-               0xd81c, 0x1002,
-               0xd81d, 0x23d2,
-               0xd81e, 0x3022,
-               0xd81f, 0x1002,
-               0xd820, 0x22cd,
-               0xd821, 0x301d,
-               0xd822, 0x27f2,
-               0xd823, 0x3022,
-               0xd824, 0x1002,
-               0xd825, 0x5553,
-               0xd826, 0x0307,
-               0xd827, 0x2522,
-               0xd828, 0x3022,
-               0xd829, 0x1002,
-               0xd82a, 0x2142,
-               0xd82b, 0x3012,
-               0xd82c, 0x1002,
-               0xd82d, 0x4016,
-               0xd82e, 0x5e63,
-               0xd82f, 0x0344,
-               0xd830, 0x2142,
-               0xd831, 0x3012,
-               0xd832, 0x1002,
-               0xd833, 0x400e,
-               0xd834, 0x2522,
-               0xd835, 0x3022,
-               0xd836, 0x1002,
-               0xd837, 0x2b52,
-               0xd838, 0x3012,
-               0xd839, 0x1002,
-               0xd83a, 0x2742,
-               0xd83b, 0x3022,
-               0xd83c, 0x1002,
-               0xd83d, 0x25e2,
-               0xd83e, 0x3022,
-               0xd83f, 0x1002,
-               0xd840, 0x2fa4,
-               0xd841, 0x3dc4,
-               0xd842, 0x6624,
-               0xd843, 0x414b,
-               0xd844, 0x56b3,
-               0xd845, 0x03c6,
-               0xd846, 0x866b,
-               0xd847, 0x400c,
-               0xd848, 0x2712,
-               0xd849, 0x3012,
-               0xd84a, 0x1002,
-               0xd84b, 0x2c4b,
-               0xd84c, 0x309b,
-               0xd84d, 0x56b3,
-               0xd84e, 0x03c3,
-               0xd84f, 0x866b,
-               0xd850, 0x400c,
-               0xd851, 0x2272,
-               0xd852, 0x3022,
-               0xd853, 0x1002,
-               0xd854, 0x2742,
-               0xd855, 0x3022,
-               0xd856, 0x1002,
-               0xd857, 0x25e2,
-               0xd858, 0x3022,
-               0xd859, 0x1002,
-               0xd85a, 0x2fb4,
-               0xd85b, 0x3dc4,
-               0xd85c, 0x6624,
-               0xd85d, 0x56b3,
-               0xd85e, 0x03c3,
-               0xd85f, 0x866b,
-               0xd860, 0x401c,
-               0xd861, 0x2c45,
-               0xd862, 0x3095,
-               0xd863, 0x5b53,
-               0xd864, 0x2372,
-               0xd865, 0x3012,
-               0xd866, 0x13c2,
-               0xd867, 0x5cc3,
-               0xd868, 0x2712,
-               0xd869, 0x3012,
-               0xd86a, 0x1312,
-               0xd86b, 0x2b52,
-               0xd86c, 0x3012,
-               0xd86d, 0x1002,
-               0xd86e, 0x2742,
-               0xd86f, 0x3022,
-               0xd870, 0x1002,
-               0xd871, 0x2582,
-               0xd872, 0x3022,
-               0xd873, 0x1002,
-               0xd874, 0x2142,
-               0xd875, 0x3012,
-               0xd876, 0x1002,
-               0xd877, 0x628f,
-               0xd878, 0x2985,
-               0xd879, 0x33a5,
-               0xd87a, 0x25e2,
-               0xd87b, 0x3022,
-               0xd87c, 0x1002,
-               0xd87d, 0x5653,
-               0xd87e, 0x03d2,
-               0xd87f, 0x401e,
-               0xd880, 0x6f72,
-               0xd881, 0x1002,
-               0xd882, 0x628f,
-               0xd883, 0x2304,
-               0xd884, 0x3c84,
-               0xd885, 0x6436,
-               0xd886, 0xdff4,
-               0xd887, 0x6436,
-               0xd888, 0x2ff5,
-               0xd889, 0x3005,
-               0xd88a, 0x8656,
-               0xd88b, 0xdfba,
-               0xd88c, 0x56a3,
-               0xd88d, 0xd05a,
-               0xd88e, 0x2972,
-               0xd88f, 0x3012,
-               0xd890, 0x1392,
-               0xd891, 0xd05a,
-               0xd892, 0x56a3,
-               0xd893, 0xdfba,
-               0xd894, 0x0383,
-               0xd895, 0x6f72,
-               0xd896, 0x1002,
-               0xd897, 0x2b45,
-               0xd898, 0x3005,
-               0xd899, 0x4178,
-               0xd89a, 0x5653,
-               0xd89b, 0x0384,
-               0xd89c, 0x2a62,
-               0xd89d, 0x3012,
-               0xd89e, 0x1002,
-               0xd89f, 0x2f05,
-               0xd8a0, 0x3005,
-               0xd8a1, 0x41c8,
-               0xd8a2, 0x5653,
-               0xd8a3, 0x0382,
-               0xd8a4, 0x0002,
-               0xd8a5, 0x4218,
-               0xd8a6, 0x2474,
-               0xd8a7, 0x3c84,
-               0xd8a8, 0x6437,
-               0xd8a9, 0xdff4,
-               0xd8aa, 0x6437,
-               0xd8ab, 0x2ff5,
-               0xd8ac, 0x3c05,
-               0xd8ad, 0x8757,
-               0xd8ae, 0xb888,
-               0xd8af, 0x9787,
-               0xd8b0, 0xdff4,
-               0xd8b1, 0x6724,
-               0xd8b2, 0x866a,
-               0xd8b3, 0x6f72,
-               0xd8b4, 0x1002,
-               0xd8b5, 0x2641,
-               0xd8b6, 0x3021,
-               0xd8b7, 0x1001,
-               0xd8b8, 0xc620,
-               0xd8b9, 0x0000,
-               0xd8ba, 0xc621,
-               0xd8bb, 0x0000,
-               0xd8bc, 0xc622,
-               0xd8bd, 0x00ce,
-               0xd8be, 0xc623,
-               0xd8bf, 0x007f,
-               0xd8c0, 0xc624,
-               0xd8c1, 0x0032,
-               0xd8c2, 0xc625,
-               0xd8c3, 0x0000,
-               0xd8c4, 0xc627,
-               0xd8c5, 0x0000,
-               0xd8c6, 0xc628,
-               0xd8c7, 0x0000,
-               0xd8c8, 0xc62c,
-               0xd8c9, 0x0000,
-               0xd8ca, 0x0000,
-               0xd8cb, 0x2641,
-               0xd8cc, 0x3021,
-               0xd8cd, 0x1001,
-               0xd8ce, 0xc502,
-               0xd8cf, 0x53ac,
-               0xd8d0, 0xc503,
-               0xd8d1, 0x2cd3,
-               0xd8d2, 0xc600,
-               0xd8d3, 0x2a6e,
-               0xd8d4, 0xc601,
-               0xd8d5, 0x2a2c,
-               0xd8d6, 0xc605,
-               0xd8d7, 0x5557,
-               0xd8d8, 0xc60c,
-               0xd8d9, 0x5400,
-               0xd8da, 0xc710,
-               0xd8db, 0x0700,
-               0xd8dc, 0xc711,
-               0xd8dd, 0x0f06,
-               0xd8de, 0xc718,
-               0xd8df, 0x0700,
-               0xd8e0, 0xc719,
-               0xd8e1, 0x0f06,
-               0xd8e2, 0xc720,
-               0xd8e3, 0x4700,
-               0xd8e4, 0xc721,
-               0xd8e5, 0x0f06,
-               0xd8e6, 0xc728,
-               0xd8e7, 0x0700,
-               0xd8e8, 0xc729,
-               0xd8e9, 0x1207,
-               0xd8ea, 0xc801,
-               0xd8eb, 0x7f50,
-               0xd8ec, 0xc802,
-               0xd8ed, 0x7760,
-               0xd8ee, 0xc803,
-               0xd8ef, 0x7fce,
-               0xd8f0, 0xc804,
-               0xd8f1, 0x520e,
-               0xd8f2, 0xc805,
-               0xd8f3, 0x5c11,
-               0xd8f4, 0xc806,
-               0xd8f5, 0x3c51,
-               0xd8f6, 0xc807,
-               0xd8f7, 0x4061,
-               0xd8f8, 0xc808,
-               0xd8f9, 0x49c1,
-               0xd8fa, 0xc809,
-               0xd8fb, 0x3840,
-               0xd8fc, 0xc80a,
-               0xd8fd, 0x0000,
-               0xd8fe, 0xc821,
-               0xd8ff, 0x0002,
-               0xd900, 0xc822,
-               0xd901, 0x0046,
-               0xd902, 0xc844,
-               0xd903, 0x182f,
-               0xd904, 0xc013,
-               0xd905, 0xf341,
-               0xd906, 0xc084,
-               0xd907, 0x0030,
-               0xd908, 0xc904,
-               0xd909, 0x1401,
-               0xd90a, 0xcb0c,
-               0xd90b, 0x0004,
-               0xd90c, 0xcb0e,
-               0xd90d, 0xa00a,
-               0xd90e, 0xcb0f,
-               0xd90f, 0xc0c0,
-               0xd910, 0xcb10,
-               0xd911, 0xc0c0,
-               0xd912, 0xcb11,
-               0xd913, 0x00a0,
-               0xd914, 0xcb12,
-               0xd915, 0x0007,
-               0xd916, 0xc241,
-               0xd917, 0xa000,
-               0xd918, 0xc243,
-               0xd919, 0x7fe0,
-               0xd91a, 0xc604,
-               0xd91b, 0x000e,
-               0xd91c, 0xc609,
-               0xd91d, 0x00f5,
-               0xd91e, 0xc611,
-               0xd91f, 0x000e,
-               0xd920, 0xc660,
-               0xd921, 0x9600,
-               0xd922, 0xc687,
-               0xd923, 0x0004,
-               0xd924, 0xc60a,
-               0xd925, 0x04f5,
-               0xd926, 0x0000,
-               0xd927, 0x2641,
-               0xd928, 0x3021,
-               0xd929, 0x1001,
-               0xd92a, 0xc620,
-               0xd92b, 0x14e5,
-               0xd92c, 0xc621,
-               0xd92d, 0xc53d,
-               0xd92e, 0xc622,
-               0xd92f, 0x3cbe,
-               0xd930, 0xc623,
-               0xd931, 0x4452,
-               0xd932, 0xc624,
-               0xd933, 0xc5c5,
-               0xd934, 0xc625,
-               0xd935, 0xe01e,
-               0xd936, 0xc627,
-               0xd937, 0x0000,
-               0xd938, 0xc628,
-               0xd939, 0x0000,
-               0xd93a, 0xc62c,
-               0xd93b, 0x0000,
-               0xd93c, 0x0000,
-               0xd93d, 0x2b84,
-               0xd93e, 0x3c74,
-               0xd93f, 0x6435,
-               0xd940, 0xdff4,
-               0xd941, 0x6435,
-               0xd942, 0x2806,
-               0xd943, 0x3006,
-               0xd944, 0x8565,
-               0xd945, 0x2b24,
-               0xd946, 0x3c24,
-               0xd947, 0x6436,
-               0xd948, 0x1002,
-               0xd949, 0x2b24,
-               0xd94a, 0x3c24,
-               0xd94b, 0x6436,
-               0xd94c, 0x4045,
-               0xd94d, 0x8656,
-               0xd94e, 0x5663,
-               0xd94f, 0x0302,
-               0xd950, 0x401e,
-               0xd951, 0x1002,
-               0xd952, 0x2807,
-               0xd953, 0x31a7,
-               0xd954, 0x20c4,
-               0xd955, 0x3c24,
-               0xd956, 0x6724,
-               0xd957, 0x1002,
-               0xd958, 0x2807,
-               0xd959, 0x3187,
-               0xd95a, 0x20c4,
-               0xd95b, 0x3c24,
-               0xd95c, 0x6724,
-               0xd95d, 0x1002,
-               0xd95e, 0x24f4,
-               0xd95f, 0x3c64,
-               0xd960, 0x6436,
-               0xd961, 0xdff4,
-               0xd962, 0x6436,
-               0xd963, 0x1002,
-               0xd964, 0x2006,
-               0xd965, 0x3d76,
-               0xd966, 0xc161,
-               0xd967, 0x6134,
-               0xd968, 0x6135,
-               0xd969, 0x5443,
-               0xd96a, 0x0303,
-               0xd96b, 0x6524,
-               0xd96c, 0x00fb,
-               0xd96d, 0x1002,
-               0xd96e, 0x20d4,
-               0xd96f, 0x3c24,
-               0xd970, 0x2025,
-               0xd971, 0x3005,
-               0xd972, 0x6524,
-               0xd973, 0x1002,
-               0xd974, 0xd019,
-               0xd975, 0x2104,
-               0xd976, 0x3c24,
-               0xd977, 0x2105,
-               0xd978, 0x3805,
-               0xd979, 0x6524,
-               0xd97a, 0xdff4,
-               0xd97b, 0x4005,
-               0xd97c, 0x6524,
-               0xd97d, 0x2e8d,
-               0xd97e, 0x303d,
-               0xd97f, 0x2408,
-               0xd980, 0x35d8,
-               0xd981, 0x5dd3,
-               0xd982, 0x0307,
-               0xd983, 0x8887,
-               0xd984, 0x63a7,
-               0xd985, 0x8887,
-               0xd986, 0x63a7,
-               0xd987, 0xdffd,
-               0xd988, 0x00f9,
-               0xd989, 0x1002,
-               0xd98a, 0x0000,
-       };
        int i, err;
 
        /* set uC clock and activate it */
@@ -1612,10 +581,16 @@ static int ael2020_setup_twinax_edc(struct cphy *phy, int modtype)
        if (err)
                return err;
 
-       /* write TWINAX EDC firmware into PHY */
-       for (i = 0; i < ARRAY_SIZE(twinax_edc) && !err; i += 2)
-               err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, twinax_edc[i],
-                                   twinax_edc[i + 1]);
+       if (phy->priv != edc_twinax)
+               err = t3_get_edc_fw(phy, EDC_TWX_AEL2020,
+                                   EDC_TWX_AEL2020_SIZE);
+       if (err)
+               return err;
+
+       for (i = 0; i <  EDC_TWX_AEL2020_SIZE / sizeof(u16) && !err; i += 2)
+               err = t3_mdio_write(phy, MDIO_MMD_PMAPMD,
+                                   phy->phy_cache[i],
+                                   phy->phy_cache[i + 1]);
        /* activate uC */
        err = set_phy_regs(phy, uCactivate);
        if (!err)
@@ -1649,9 +624,39 @@ static int ael2020_get_module_type(struct cphy *phy, int delay_ms)
  */
 static int ael2020_intr_enable(struct cphy *phy)
 {
-       int err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, AEL2020_GPIO_CTRL,
-                               0x2 << (AEL2020_GPIO_MODDET*4));
-       return err ? err : t3_phy_lasi_intr_enable(phy);
+       struct reg_val regs[] = {
+               /* output Module's Loss Of Signal (LOS) to LED */
+               { MDIO_MMD_PMAPMD, AEL2020_GPIO_CFG+AEL2020_GPIO_LSTAT,
+                       0xffff, 0x4 },
+               { MDIO_MMD_PMAPMD, AEL2020_GPIO_CTRL,
+                       0xffff, 0x8 << (AEL2020_GPIO_LSTAT*4) },
+
+                /* enable module detect status change interrupts */
+               { MDIO_MMD_PMAPMD, AEL2020_GPIO_CTRL,
+                       0xffff, 0x2 << (AEL2020_GPIO_MODDET*4) },
+
+               /* end */
+               { 0, 0, 0, 0 }
+       };
+       int err, link_ok = 0;
+
+       /* set up "link status" LED and enable module change interrupts */
+       err = set_phy_regs(phy, regs);
+       if (err)
+               return err;
+
+       err = get_link_status_r(phy, &link_ok, NULL, NULL, NULL);
+       if (err)
+               return err;
+       if (link_ok)
+               t3_link_changed(phy->adapter,
+                               phy2portid(phy));
+
+       err = t3_phy_lasi_intr_enable(phy);
+       if (err)
+               return err;
+
+       return 0;
 }
 
 /*
@@ -1659,9 +664,26 @@ static int ael2020_intr_enable(struct cphy *phy)
  */
 static int ael2020_intr_disable(struct cphy *phy)
 {
-       int err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, AEL2020_GPIO_CTRL,
-                               0x1 << (AEL2020_GPIO_MODDET*4));
-       return err ? err : t3_phy_lasi_intr_disable(phy);
+       struct reg_val regs[] = {
+               /* reset "link status" LED to "off" */
+               { MDIO_MMD_PMAPMD, AEL2020_GPIO_CTRL,
+                       0xffff, 0xb << (AEL2020_GPIO_LSTAT*4) },
+
+               /* disable module detect status change interrupts */
+               { MDIO_MMD_PMAPMD, AEL2020_GPIO_CTRL,
+                       0xffff, 0x1 << (AEL2020_GPIO_MODDET*4) },
+
+               /* end */
+               { 0, 0, 0, 0 }
+       };
+       int err;
+
+       /* turn off "link status" LED and disable module change interrupts */
+       err = set_phy_regs(phy, regs);
+       if (err)
+               return err;
+
+       return t3_phy_lasi_intr_disable(phy);
 }
 
 /*
@@ -1679,31 +701,26 @@ static int ael2020_intr_clear(struct cphy *phy)
        return err ? err : t3_phy_lasi_intr_clear(phy);
 }
 
+static struct reg_val ael2020_reset_regs[] = {
+       /* Erratum #2: CDRLOL asserted, causing PMA link down status */
+       { MDIO_MMD_PMAPMD, 0xc003, 0xffff, 0x3101 },
+
+       /* force XAUI to send LF when RX_LOS is asserted */
+       { MDIO_MMD_PMAPMD, 0xcd40, 0xffff, 0x0001 },
+
+       /* allow writes to transceiver module EEPROM on i2c bus */
+       { MDIO_MMD_PMAPMD, 0xff02, 0xffff, 0x0023 },
+       { MDIO_MMD_PMAPMD, 0xff03, 0xffff, 0x0000 },
+       { MDIO_MMD_PMAPMD, 0xff04, 0xffff, 0x0000 },
+
+       /* end */
+       { 0, 0, 0, 0 }
+};
 /*
  * Reset the PHY and put it into a canonical operating state.
  */
 static int ael2020_reset(struct cphy *phy, int wait)
 {
-       static struct reg_val regs0[] = {
-               /* Erratum #2: CDRLOL asserted, causing PMA link down status */
-               { MDIO_MMD_PMAPMD, 0xc003, 0xffff, 0x3101 },
-
-               /* force XAUI to send LF when RX_LOS is asserted */
-               { MDIO_MMD_PMAPMD, 0xcd40, 0xffff, 0x0001 },
-
-               /* RX_LOS pin is active high */
-               { MDIO_MMD_PMAPMD, AEL_OPT_SETTINGS,
-                       0x0020, 0x0020 },
-
-               /* output Module's Loss Of Signal (LOS) to LED */
-               { MDIO_MMD_PMAPMD, AEL2020_GPIO_CFG+AEL2020_GPIO_LSTAT,
-                       0xffff, 0x0004 },
-               { MDIO_MMD_PMAPMD, AEL2020_GPIO_CTRL,
-                       0xffff, 0x8 << (AEL2020_GPIO_LSTAT*4) },
-
-               /* end */
-               { 0, 0, 0, 0 }
-       };
        int err;
        unsigned int lasi_ctrl;
 
@@ -1720,7 +737,7 @@ static int ael2020_reset(struct cphy *phy, int wait)
 
        /* basic initialization for all module types */
        phy->priv = edc_none;
-       err = set_phy_regs(phy, regs0);
+       err = set_phy_regs(phy, ael2020_reset_regs);
        if (err)
                return err;
 
@@ -1798,10 +815,16 @@ static struct cphy_ops ael2020_ops = {
 int t3_ael2020_phy_prep(struct cphy *phy, struct adapter *adapter, int phy_addr,
                        const struct mdio_ops *mdio_ops)
 {
+       int err;
+
        cphy_init(phy, adapter, phy_addr, &ael2020_ops, mdio_ops,
                  SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_FIBRE |
                  SUPPORTED_IRQ, "10GBASE-R");
        msleep(125);
+
+       err = set_phy_regs(phy, ael2020_reset_regs);
+       if (err)
+               return err;
        return 0;
 }
 
@@ -1840,7 +863,7 @@ static struct cphy_ops qt2045_ops = {
        .intr_clear = t3_phy_lasi_intr_clear,
        .intr_handler = t3_phy_lasi_intr_handler,
        .get_link_status = get_link_status_x,
-       .power_down = ael1006_power_down,
+       .power_down = ael1002_power_down,
        .mmds = MDIO_DEVS_PMAPMD | MDIO_DEVS_PCS | MDIO_DEVS_PHYXS,
 };
 
index b1fd5bf..341b7ef 100644 (file)
@@ -271,7 +271,8 @@ int t3_aq100x_phy_prep(struct cphy *phy, struct adapter *adapter, int phy_addr,
 
        cphy_init(phy, adapter, phy_addr, &aq100x_ops, mdio_ops,
                  SUPPORTED_1000baseT_Full | SUPPORTED_10000baseT_Full |
-                 SUPPORTED_Autoneg | SUPPORTED_AUI, "1000/10GBASE-T");
+                 SUPPORTED_TP | SUPPORTED_Autoneg | SUPPORTED_AUI,
+                 "1000/10GBASE-T");
 
        /*
         * The PHY has been out of reset ever since the system powered up.  So
@@ -316,11 +317,9 @@ int t3_aq100x_phy_prep(struct cphy *phy, struct adapter *adapter, int phy_addr,
 
        /* Firmware version check. */
        t3_mdio_read(phy, MDIO_MMD_VEND1, AQ_FW_VERSION, &v);
-       if (v != 30) {
+       if (v != 101)
                CH_WARN(adapter, "PHY%d: unsupported firmware %d\n",
                        phy_addr, v);
-               return 0; /* allow t3_prep_adapter to succeed */
-       }
 
        /*
         * The PHY should start in really-low-power mode.  Prepare it for normal
index d21b705..1b2c305 100644 (file)
@@ -566,6 +566,15 @@ struct cphy_ops {
 
        u32 mmds;
 };
+enum {
+       EDC_OPT_AEL2005 = 0,
+       EDC_OPT_AEL2005_SIZE = 1084,
+       EDC_TWX_AEL2005 = 1,
+       EDC_TWX_AEL2005_SIZE = 1464,
+       EDC_TWX_AEL2020 = 2,
+       EDC_TWX_AEL2020_SIZE = 1628,
+       EDC_MAX_SIZE = EDC_TWX_AEL2020_SIZE, /* Max cache size */
+};
 
 /* A PHY instance */
 struct cphy {
@@ -577,6 +586,7 @@ struct cphy {
        unsigned long fifo_errors;      /* FIFO over/under-flows */
        const struct cphy_ops *ops;     /* PHY operations */
        struct mdio_if_info mdio;
+       u16 phy_cache[EDC_MAX_SIZE];    /* EDC cache */
 };
 
 /* Convenience MDIO read/write wrappers */
index fb5df5c..ec05149 100644 (file)
@@ -172,6 +172,23 @@ static void link_report(struct net_device *dev)
        }
 }
 
+static void enable_tx_fifo_drain(struct adapter *adapter,
+                                struct port_info *pi)
+{
+       t3_set_reg_field(adapter, A_XGM_TXFIFO_CFG + pi->mac.offset, 0,
+                        F_ENDROPPKT);
+       t3_write_reg(adapter, A_XGM_RX_CTRL + pi->mac.offset, 0);
+       t3_write_reg(adapter, A_XGM_TX_CTRL + pi->mac.offset, F_TXEN);
+       t3_write_reg(adapter, A_XGM_RX_CTRL + pi->mac.offset, F_RXEN);
+}
+
+static void disable_tx_fifo_drain(struct adapter *adapter,
+                                 struct port_info *pi)
+{
+       t3_set_reg_field(adapter, A_XGM_TXFIFO_CFG + pi->mac.offset,
+                        F_ENDROPPKT, 0);
+}
+
 void t3_os_link_fault(struct adapter *adap, int port_id, int state)
 {
        struct net_device *dev = adap->port[port_id];
@@ -185,6 +202,8 @@ void t3_os_link_fault(struct adapter *adap, int port_id, int state)
 
                netif_carrier_on(dev);
 
+               disable_tx_fifo_drain(adap, pi);
+
                /* Clear local faults */
                t3_xgm_intr_disable(adap, pi->port_id);
                t3_read_reg(adap, A_XGM_INT_STATUS +
@@ -200,9 +219,12 @@ void t3_os_link_fault(struct adapter *adap, int port_id, int state)
                t3_xgm_intr_enable(adap, pi->port_id);
 
                t3_mac_enable(mac, MAC_DIRECTION_TX);
-       } else
+       } else {
                netif_carrier_off(dev);
 
+               /* Flush TX FIFO */
+               enable_tx_fifo_drain(adap, pi);
+       }
        link_report(dev);
 }
 
@@ -232,6 +254,8 @@ void t3_os_link_changed(struct adapter *adapter, int port_id, int link_stat,
 
        if (link_stat != netif_carrier_ok(dev)) {
                if (link_stat) {
+                       disable_tx_fifo_drain(adapter, pi);
+
                        t3_mac_enable(mac, MAC_DIRECTION_RX);
 
                        /* Clear local faults */
@@ -263,6 +287,9 @@ void t3_os_link_changed(struct adapter *adapter, int port_id, int link_stat,
                        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);
+
+                       /* Flush TX FIFO */
+                       enable_tx_fifo_drain(adapter, pi);
                }
 
                link_report(dev);
@@ -443,6 +470,7 @@ static int init_tp_parity(struct adapter *adap)
                memset(req, 0, sizeof(*req));
                req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
                OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SMT_WRITE_REQ, i));
+               req->mtu_idx = NMTUS - 1;
                req->iff = i;
                t3_mgmt_tx(adap, skb);
                if (skb == adap->nofail_skb) {
@@ -963,6 +991,75 @@ static int bind_qsets(struct adapter *adap)
 
 #define FW_FNAME "cxgb3/t3fw-%d.%d.%d.bin"
 #define TPSRAM_NAME "cxgb3/t3%c_psram-%d.%d.%d.bin"
+#define AEL2005_OPT_EDC_NAME "cxgb3/ael2005_opt_edc.bin"
+#define AEL2005_TWX_EDC_NAME "cxgb3/ael2005_twx_edc.bin"
+#define AEL2020_TWX_EDC_NAME "cxgb3/ael2005_twx_edc.bin"
+
+static inline const char *get_edc_fw_name(int edc_idx)
+{
+       const char *fw_name = NULL;
+
+       switch (edc_idx) {
+       case EDC_OPT_AEL2005:
+               fw_name = AEL2005_OPT_EDC_NAME;
+               break;
+       case EDC_TWX_AEL2005:
+               fw_name = AEL2005_TWX_EDC_NAME;
+               break;
+       case EDC_TWX_AEL2020:
+               fw_name = AEL2020_TWX_EDC_NAME;
+               break;
+       }
+       return fw_name;
+}
+
+int t3_get_edc_fw(struct cphy *phy, int edc_idx, int size)
+{
+       struct adapter *adapter = phy->adapter;
+       const struct firmware *fw;
+       char buf[64];
+       u32 csum;
+       const __be32 *p;
+       u16 *cache = phy->phy_cache;
+       int i, ret;
+
+       snprintf(buf, sizeof(buf), get_edc_fw_name(edc_idx));
+
+       ret = request_firmware(&fw, buf, &adapter->pdev->dev);
+       if (ret < 0) {
+               dev_err(&adapter->pdev->dev,
+                       "could not upgrade firmware: unable to load %s\n",
+                       buf);
+               return ret;
+       }
+
+       /* check size, take checksum in account */
+       if (fw->size > size + 4) {
+               CH_ERR(adapter, "firmware image too large %u, expected %d\n",
+                      (unsigned int)fw->size, size + 4);
+               ret = -EINVAL;
+       }
+
+       /* compute checksum */
+       p = (const __be32 *)fw->data;
+       for (csum = 0, i = 0; i < fw->size / sizeof(csum); i++)
+               csum += ntohl(p[i]);
+
+       if (csum != 0xffffffff) {
+               CH_ERR(adapter, "corrupted firmware image, checksum %u\n",
+                      csum);
+               ret = -EINVAL;
+       }
+
+       for (i = 0; i < size / 4 ; i++) {
+               *cache++ = (be32_to_cpu(p[i]) & 0xffff0000) >> 16;
+               *cache++ = be32_to_cpu(p[i]) & 0xffff;
+       }
+
+       release_firmware(fw);
+
+       return ret;
+}
 
 static int upgrade_fw(struct adapter *adap)
 {
index 870d449..e78d341 100644 (file)
@@ -3682,6 +3682,8 @@ static void mc7_prep(struct adapter *adapter, struct mc7 *mc7,
 void mac_prep(struct cmac *mac, struct adapter *adapter, int index)
 {
        mac->adapter = adapter;
+       if (!adapter->params.vpd.xauicfg[1])
+               index = 0;
        mac->offset = (XGMAC0_1_BASE_ADDR - XGMAC0_0_BASE_ADDR) * index;
        mac->nucast = 1;
 
index f87f943..0109ee4 100644 (file)
@@ -447,11 +447,12 @@ int t3_mac_set_speed_duplex_fc(struct cmac *mac, int speed, int duplex, int fc)
 
        val = t3_read_reg(adap, A_XGM_RXFIFO_CFG + oft);
        val &= ~V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM);
-       if (fc & PAUSE_TX)
-               val |= V_RXFIFOPAUSEHWM(rx_fifo_hwm(
-                                               t3_read_reg(adap,
-                                               A_XGM_RX_MAX_PKT_SIZE
-                                               + oft)) / 8);
+       if (fc & PAUSE_TX) {
+               u32 rx_max_pkt_size =
+                   G_RXMAXPKTSIZE(t3_read_reg(adap,
+                                              A_XGM_RX_MAX_PKT_SIZE + oft));
+               val |= V_RXFIFOPAUSEHWM(rx_fifo_hwm(rx_max_pkt_size) / 8);
+       }
        t3_write_reg(adap, A_XGM_RXFIFO_CFG + oft, val);
 
        t3_set_reg_field(adap, A_XGM_TX_CFG + oft, F_TXPAUSEEN,
index e1af089..6b13f4f 100644 (file)
@@ -226,7 +226,7 @@ static int de600_start_xmit(struct sk_buff *skb, struct net_device *dev)
        }
        spin_unlock_irqrestore(&de600_lock, flags);
        dev_kfree_skb(skb);
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 /*
index 55d2bb6..45794f6 100644 (file)
@@ -542,7 +542,7 @@ static int de620_start_xmit(struct sk_buff *skb, struct net_device *dev)
        dev->stats.tx_packets++;
        spin_unlock_irqrestore(&de620_lock, flags);
        dev_kfree_skb (skb);
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 /*****************************************************
index 2b22e58..a31696a 100644 (file)
@@ -902,7 +902,7 @@ static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
        if (len < ETH_ZLEN) {
                if (skb_padto(skb, ETH_ZLEN))
-                       return 0;
+                       return NETDEV_TX_OK;
                len = ETH_ZLEN;
        }
 
@@ -933,7 +933,7 @@ static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev)
        dev->trans_start = jiffies;
        dev_kfree_skb(skb);
 
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 static void lance_load_multicast(struct net_device *dev)
index 102b8d4..b2e0a8f 100644 (file)
@@ -3218,7 +3218,7 @@ static int dfx_xmt_queue_pkt(
                bp->xmt_length_errors++;                /* bump error counter */
                netif_wake_queue(dev);
                dev_kfree_skb(skb);
-               return(0);                              /* return "success" */
+               return NETDEV_TX_OK;                    /* return "success" */
        }
        /*
         * See if adapter link is available, if not, free buffer
@@ -3241,7 +3241,7 @@ static int dfx_xmt_queue_pkt(
                        bp->xmt_discards++;                                     /* bump error counter */
                        dev_kfree_skb(skb);             /* free sk_buff now */
                        netif_wake_queue(dev);
-                       return(0);                                                      /* return "success" */
+                       return NETDEV_TX_OK;            /* return "success" */
                        }
                }
 
@@ -3345,7 +3345,7 @@ static int dfx_xmt_queue_pkt(
        dfx_port_write_long(bp, PI_PDQ_K_REG_TYPE_2_PROD, bp->rcv_xmt_reg.lword);
        spin_unlock_irqrestore(&bp->lock, flags);
        netif_wake_queue(dev);
-       return(0);                                                      /* packet queued to adapter */
+       return NETDEV_TX_OK;    /* packet queued to adapter */
        }
 
 
index 97ea2d6..adb997c 100644 (file)
@@ -1793,7 +1793,7 @@ static int __init get_hw_addr(struct net_device *dev)
 static int load_packet(struct net_device *dev, struct sk_buff *skb)
 {
        struct depca_private *lp = netdev_priv(dev);
-       int i, entry, end, len, status = 0;
+       int i, entry, end, len, status = NETDEV_TX_OK;
 
        entry = lp->tx_new;     /* Ring around buffer number. */
        end = (entry + (skb->len - 1) / TX_BUFF_SZ) & lp->txRingMask;
index dd771de..a2bc415 100644 (file)
@@ -92,6 +92,7 @@ typedef struct board_info {
        u16             tx_pkt_cnt;
        u16             queue_pkt_len;
        u16             queue_start_addr;
+       u16             queue_ip_summed;
        u16             dbug_cnt;
        u8              io_mode;                /* 0:word, 2:byte */
        u8              phy_addr;
@@ -124,6 +125,10 @@ typedef struct board_info {
 
        struct mii_if_info mii;
        u32             msg_enable;
+
+       int             rx_csum;
+       int             can_csum;
+       int             ip_summed;
 } board_info_t;
 
 /* debug code */
@@ -460,6 +465,40 @@ static int dm9000_nway_reset(struct net_device *dev)
        return mii_nway_restart(&dm->mii);
 }
 
+static uint32_t dm9000_get_rx_csum(struct net_device *dev)
+{
+       board_info_t *dm = to_dm9000_board(dev);
+       return dm->rx_csum;
+}
+
+static int dm9000_set_rx_csum(struct net_device *dev, uint32_t data)
+{
+       board_info_t *dm = to_dm9000_board(dev);
+       unsigned long flags;
+
+       if (dm->can_csum) {
+               dm->rx_csum = data;
+
+               spin_lock_irqsave(&dm->lock, flags);
+               iow(dm, DM9000_RCSR, dm->rx_csum ? RCSR_CSUM : 0);
+               spin_unlock_irqrestore(&dm->lock, flags);
+
+               return 0;
+       }
+
+       return -EOPNOTSUPP;
+}
+
+static int dm9000_set_tx_csum(struct net_device *dev, uint32_t data)
+{
+       board_info_t *dm = to_dm9000_board(dev);
+       int ret = -EOPNOTSUPP;
+
+       if (dm->can_csum)
+               ret = ethtool_op_set_tx_csum(dev, data);
+       return ret;
+}
+
 static u32 dm9000_get_link(struct net_device *dev)
 {
        board_info_t *dm = to_dm9000_board(dev);
@@ -540,6 +579,10 @@ static const struct ethtool_ops dm9000_ethtool_ops = {
        .get_eeprom_len         = dm9000_get_eeprom_len,
        .get_eeprom             = dm9000_get_eeprom,
        .set_eeprom             = dm9000_set_eeprom,
+       .get_rx_csum            = dm9000_get_rx_csum,
+       .set_rx_csum            = dm9000_set_rx_csum,
+       .get_tx_csum            = ethtool_op_get_tx_csum,
+       .set_tx_csum            = dm9000_set_tx_csum,
 };
 
 static void dm9000_show_carrier(board_info_t *db,
@@ -685,6 +728,9 @@ dm9000_init_dm9000(struct net_device *dev)
        /* I/O mode */
        db->io_mode = ior(db, DM9000_ISR) >> 6; /* ISR bit7:6 keeps I/O mode */
 
+       /* Checksum mode */
+       dm9000_set_rx_csum(dev, db->rx_csum);
+
        /* GPIO0 on pre-activate PHY */
        iow(db, DM9000_GPR, 0); /* REG_1F bit0 activate phyxcer */
        iow(db, DM9000_GPCR, GPCR_GEP_CNTL);    /* Let GPIO0 output */
@@ -743,6 +789,29 @@ static void dm9000_timeout(struct net_device *dev)
        spin_unlock_irqrestore(&db->lock, flags);
 }
 
+static void dm9000_send_packet(struct net_device *dev,
+                              int ip_summed,
+                              u16 pkt_len)
+{
+       board_info_t *dm = to_dm9000_board(dev);
+
+       /* The DM9000 is not smart enough to leave fragmented packets alone. */
+       if (dm->ip_summed != ip_summed) {
+               if (ip_summed == CHECKSUM_NONE)
+                       iow(dm, DM9000_TCCR, 0);
+               else
+                       iow(dm, DM9000_TCCR, TCCR_IP | TCCR_UDP | TCCR_TCP);
+               dm->ip_summed = ip_summed;
+       }
+
+       /* Set TX length to DM9000 */
+       iow(dm, DM9000_TXPLL, pkt_len);
+       iow(dm, DM9000_TXPLH, pkt_len >> 8);
+
+       /* Issue TX polling command */
+       iow(dm, DM9000_TCR, TCR_TXREQ); /* Cleared after TX complete */
+}
+
 /*
  *  Hardware start transmission.
  *  Send a packet to media from the upper layer.
@@ -769,17 +838,11 @@ dm9000_start_xmit(struct sk_buff *skb, struct net_device *dev)
        db->tx_pkt_cnt++;
        /* TX control: First packet immediately send, second packet queue */
        if (db->tx_pkt_cnt == 1) {
-               /* Set TX length to DM9000 */
-               iow(db, DM9000_TXPLL, skb->len);
-               iow(db, DM9000_TXPLH, skb->len >> 8);
-
-               /* Issue TX polling command */
-               iow(db, DM9000_TCR, TCR_TXREQ); /* Cleared after TX complete */
-
-               dev->trans_start = jiffies;     /* save the time stamp */
+               dm9000_send_packet(dev, skb->ip_summed, skb->len);
        } else {
                /* Second packet */
                db->queue_pkt_len = skb->len;
+               db->queue_ip_summed = skb->ip_summed;
                netif_stop_queue(dev);
        }
 
@@ -788,7 +851,7 @@ dm9000_start_xmit(struct sk_buff *skb, struct net_device *dev)
        /* free this SKB */
        dev_kfree_skb(skb);
 
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 /*
@@ -809,12 +872,9 @@ static void dm9000_tx_done(struct net_device *dev, board_info_t *db)
                        dev_dbg(db->dev, "tx done, NSR %02x\n", tx_status);
 
                /* Queue packet check & send */
-               if (db->tx_pkt_cnt > 0) {
-                       iow(db, DM9000_TXPLL, db->queue_pkt_len);
-                       iow(db, DM9000_TXPLH, db->queue_pkt_len >> 8);
-                       iow(db, DM9000_TCR, TCR_TXREQ);
-                       dev->trans_start = jiffies;
-               }
+               if (db->tx_pkt_cnt > 0)
+                       dm9000_send_packet(dev, db->queue_ip_summed,
+                                          db->queue_pkt_len);
                netif_wake_queue(dev);
        }
 }
@@ -846,14 +906,14 @@ dm9000_rx(struct net_device *dev)
                rxbyte = readb(db->io_data);
 
                /* Status check: this byte must be 0 or 1 */
-               if (rxbyte > DM9000_PKT_RDY) {
+               if (rxbyte & DM9000_PKT_ERR) {
                        dev_warn(db->dev, "status check fail: %d\n", rxbyte);
                        iow(db, DM9000_RCR, 0x00);      /* Stop Device */
                        iow(db, DM9000_ISR, IMR_PAR);   /* Stop INT request */
                        return;
                }
 
-               if (rxbyte != DM9000_PKT_RDY)
+               if (!(rxbyte & DM9000_PKT_RDY))
                        return;
 
                /* A packet ready now  & Get status/length */
@@ -914,6 +974,12 @@ dm9000_rx(struct net_device *dev)
 
                        /* Pass to upper layer */
                        skb->protocol = eth_type_trans(skb, dev);
+                       if (db->rx_csum) {
+                               if ((((rxbyte & 0x1c) << 3) & rxbyte) == 0)
+                                       skb->ip_summed = CHECKSUM_UNNECESSARY;
+                               else
+                                       skb->ip_summed = CHECKSUM_NONE;
+                       }
                        netif_rx(skb);
                        dev->stats.rx_packets++;
 
@@ -922,7 +988,7 @@ dm9000_rx(struct net_device *dev)
 
                        (db->dumpblk)(db->io_data, RxLen);
                }
-       } while (rxbyte == DM9000_PKT_RDY);
+       } while (rxbyte & DM9000_PKT_RDY);
 }
 
 static irqreturn_t dm9000_interrupt(int irq, void *dev_id)
@@ -1349,6 +1415,13 @@ dm9000_probe(struct platform_device *pdev)
                db->type = TYPE_DM9000E;
        }
 
+       /* dm9000a/b are capable of hardware checksum offload */
+       if (db->type == TYPE_DM9000A || db->type == TYPE_DM9000B) {
+               db->can_csum = 1;
+               db->rx_csum = 1;
+               ndev->features |= NETIF_F_IP_CSUM;
+       }
+
        /* from this point we assume that we have found a DM9000 */
 
        /* driver system function */
@@ -1410,9 +1483,10 @@ out:
 }
 
 static int
-dm9000_drv_suspend(struct platform_device *dev, pm_message_t state)
+dm9000_drv_suspend(struct device *dev)
 {
-       struct net_device *ndev = platform_get_drvdata(dev);
+       struct platform_device *pdev = to_platform_device(dev);
+       struct net_device *ndev = platform_get_drvdata(pdev);
        board_info_t *db;
 
        if (ndev) {
@@ -1428,9 +1502,10 @@ dm9000_drv_suspend(struct platform_device *dev, pm_message_t state)
 }
 
 static int
-dm9000_drv_resume(struct platform_device *dev)
+dm9000_drv_resume(struct device *dev)
 {
-       struct net_device *ndev = platform_get_drvdata(dev);
+       struct platform_device *pdev = to_platform_device(dev);
+       struct net_device *ndev = platform_get_drvdata(pdev);
        board_info_t *db = netdev_priv(ndev);
 
        if (ndev) {
@@ -1447,6 +1522,11 @@ dm9000_drv_resume(struct platform_device *dev)
        return 0;
 }
 
+static struct dev_pm_ops dm9000_drv_pm_ops = {
+       .suspend        = dm9000_drv_suspend,
+       .resume         = dm9000_drv_resume,
+};
+
 static int __devexit
 dm9000_drv_remove(struct platform_device *pdev)
 {
@@ -1466,11 +1546,10 @@ static struct platform_driver dm9000_driver = {
        .driver = {
                .name    = "dm9000",
                .owner   = THIS_MODULE,
+               .pm      = &dm9000_drv_pm_ops,
        },
        .probe   = dm9000_probe,
        .remove  = __devexit_p(dm9000_drv_remove),
-       .suspend = dm9000_drv_suspend,
-       .resume  = dm9000_drv_resume,
 };
 
 static int __init
index ba25cf5..80817c2 100644 (file)
 #define DM9000_CHIPR           0x2C
 #define DM9000_SMCR            0x2F
 
+#define DM9000_ETXCSR          0x30
+#define DM9000_TCCR           0x31
+#define DM9000_RCSR           0x32
+
 #define CHIPR_DM9000A         0x19
 #define CHIPR_DM9000B         0x1B
 
 
 #define GPCR_GEP_CNTL       (1<<0)
 
+#define TCCR_IP                    (1<<0)
+#define TCCR_TCP           (1<<1)
+#define TCCR_UDP           (1<<2)
+
+#define RCSR_UDP_BAD       (1<<7)
+#define RCSR_TCP_BAD       (1<<6)
+#define RCSR_IP_BAD        (1<<5)
+#define RCSR_UDP           (1<<4)
+#define RCSR_TCP           (1<<3)
+#define RCSR_IP                    (1<<2)
+#define RCSR_CSUM          (1<<1)
+#define RCSR_DISCARD       (1<<0)
+
 #define DM9000_PKT_RDY         0x01    /* Packet ready to receive */
+#define DM9000_PKT_ERR         0x02
 #define DM9000_PKT_MAX         1536    /* Received packet max size */
 
 /* DM9000A / DM9000B definitions */
index 33fa9ee..2818d5d 100644 (file)
@@ -596,7 +596,7 @@ static int dnet_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
        dev->trans_start = jiffies;
 
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 static void dnet_reset_hw(struct dnet *bp)
index 8ebd7d7..713ce6c 100644 (file)
@@ -85,7 +85,7 @@ static int dummy_xmit(struct sk_buff *skb, struct net_device *dev)
        dev->stats.tx_bytes += skb->len;
 
        dev_kfree_skb(skb);
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 static int dummy_validate(struct nlattr *tb[], struct nlattr *data[])
index 41b648a..569df19 100644 (file)
@@ -1720,7 +1720,7 @@ static int e100_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
        }
 
        netdev->trans_start = jiffies;
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 static int e100_tx_clean(struct nic *nic)
index e9a416f..1a4f89c 100644 (file)
@@ -111,6 +111,9 @@ do {                                                                        \
 #define E1000_MIN_RXD                       80
 #define E1000_MAX_82544_RXD               4096
 
+#define E1000_MIN_ITR_USECS            10 /* 100000 irq/sec */
+#define E1000_MAX_ITR_USECS            10000 /* 100    irq/sec */
+
 /* this is the size past which hardware will drop packets when setting LPE=0 */
 #define MAXIMUM_ETHERNET_VLAN_SIZE 1522
 
@@ -137,7 +140,7 @@ do {                                                                        \
 #define E1000_FC_HIGH_DIFF 0x1638  /* High: 5688 bytes below Rx FIFO size */
 #define E1000_FC_LOW_DIFF 0x1640   /* Low:  5696 bytes below Rx FIFO size */
 
-#define E1000_FC_PAUSE_TIME 0x0680 /* 858 usec */
+#define E1000_FC_PAUSE_TIME 0xFFFF /* pause for the max or until send xon */
 
 /* How many Tx Descriptors do we need to call netif_wake_queue ? */
 #define E1000_TX_QUEUE_WAKE    16
@@ -161,6 +164,7 @@ do {                                                                        \
 struct e1000_buffer {
        struct sk_buff *skb;
        dma_addr_t dma;
+       struct page *page;
        unsigned long time_stamp;
        u16 length;
        u16 next_to_watch;
@@ -202,6 +206,7 @@ struct e1000_rx_ring {
        unsigned int next_to_clean;
        /* array of buffer information structs */
        struct e1000_buffer *buffer_info;
+       struct sk_buff *rx_skb_top;
 
        /* cpu for rx queue */
        int cpu;
index c854c96..27f996a 100644 (file)
@@ -1904,6 +1904,53 @@ static int e1000_phys_id(struct net_device *netdev, u32 data)
        return 0;
 }
 
+static int e1000_get_coalesce(struct net_device *netdev,
+                             struct ethtool_coalesce *ec)
+{
+       struct e1000_adapter *adapter = netdev_priv(netdev);
+
+       if (adapter->hw.mac_type < e1000_82545)
+               return -EOPNOTSUPP;
+
+       if (adapter->itr_setting <= 3)
+               ec->rx_coalesce_usecs = adapter->itr_setting;
+       else
+               ec->rx_coalesce_usecs = 1000000 / adapter->itr_setting;
+
+       return 0;
+}
+
+static int e1000_set_coalesce(struct net_device *netdev,
+                             struct ethtool_coalesce *ec)
+{
+       struct e1000_adapter *adapter = netdev_priv(netdev);
+       struct e1000_hw *hw = &adapter->hw;
+
+       if (hw->mac_type < e1000_82545)
+               return -EOPNOTSUPP;
+
+       if ((ec->rx_coalesce_usecs > E1000_MAX_ITR_USECS) ||
+           ((ec->rx_coalesce_usecs > 3) &&
+            (ec->rx_coalesce_usecs < E1000_MIN_ITR_USECS)) ||
+           (ec->rx_coalesce_usecs == 2))
+               return -EINVAL;
+
+       if (ec->rx_coalesce_usecs <= 3) {
+               adapter->itr = 20000;
+               adapter->itr_setting = ec->rx_coalesce_usecs;
+       } else {
+               adapter->itr = (1000000 / ec->rx_coalesce_usecs);
+               adapter->itr_setting = adapter->itr & ~3;
+       }
+
+       if (adapter->itr_setting != 0)
+               ew32(ITR, 1000000000 / (adapter->itr * 256));
+       else
+               ew32(ITR, 0);
+
+       return 0;
+}
+
 static int e1000_nway_reset(struct net_device *netdev)
 {
        struct e1000_adapter *adapter = netdev_priv(netdev);
@@ -1978,7 +2025,9 @@ static const struct ethtool_ops e1000_ethtool_ops = {
        .get_strings            = e1000_get_strings,
        .phys_id                = e1000_phys_id,
        .get_ethtool_stats      = e1000_get_ethtool_stats,
-       .get_sset_count         = e1000_get_sset_count,
+       .get_sset_count         = e1000_get_sset_count,
+       .get_coalesce           = e1000_get_coalesce,
+       .set_coalesce           = e1000_set_coalesce,
 };
 
 void e1000_set_ethtool_ops(struct net_device *netdev)
index e1a3fc1..1e5ae11 100644 (file)
@@ -1955,7 +1955,7 @@ static s32 e1000_setup_copper_link(struct e1000_hw *hw)
     s32 ret_val;
     u16 i;
     u16 phy_data;
-    u16 reg_data;
+    u16 reg_data = 0;
 
     DEBUGFUNC("e1000_setup_copper_link");
 
index 99fce2c..a8866bd 100644 (file)
@@ -523,11 +523,8 @@ s32 e1000_check_phy_reset_block(struct e1000_hw *hw);
 
 /* The sizes (in bytes) of a ethernet packet */
 #define ENET_HEADER_SIZE             14
-#define MAXIMUM_ETHERNET_FRAME_SIZE  1518 /* With FCS */
 #define MINIMUM_ETHERNET_FRAME_SIZE  64   /* With FCS */
 #define ETHERNET_FCS_SIZE            4
-#define MAXIMUM_ETHERNET_PACKET_SIZE \
-    (MAXIMUM_ETHERNET_FRAME_SIZE - ETHERNET_FCS_SIZE)
 #define MINIMUM_ETHERNET_PACKET_SIZE \
     (MINIMUM_ETHERNET_FRAME_SIZE - ETHERNET_FCS_SIZE)
 #define CRC_LENGTH                   ETHERNET_FCS_SIZE
index 5b8cbdb..d7df00c 100644 (file)
@@ -137,9 +137,15 @@ static int e1000_clean(struct napi_struct *napi, int budget);
 static bool e1000_clean_rx_irq(struct e1000_adapter *adapter,
                               struct e1000_rx_ring *rx_ring,
                               int *work_done, int work_to_do);
+static bool e1000_clean_jumbo_rx_irq(struct e1000_adapter *adapter,
+                                    struct e1000_rx_ring *rx_ring,
+                                    int *work_done, int work_to_do);
 static void e1000_alloc_rx_buffers(struct e1000_adapter *adapter,
-                                   struct e1000_rx_ring *rx_ring,
+                                  struct e1000_rx_ring *rx_ring,
                                   int cleaned_count);
+static void e1000_alloc_jumbo_rx_buffers(struct e1000_adapter *adapter,
+                                        struct e1000_rx_ring *rx_ring,
+                                        int cleaned_count);
 static int e1000_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd);
 static int e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr,
                           int cmd);
@@ -635,8 +641,8 @@ void e1000_reset(struct e1000_adapter *adapter)
 {
        struct e1000_hw *hw = &adapter->hw;
        u32 pba = 0, tx_space, min_tx_space, min_rx_space;
-       u16 fc_high_water_mark = E1000_FC_HIGH_DIFF;
        bool legacy_pba_adjust = false;
+       u16 hwm;
 
        /* Repartition Pba for greater than 9k mtu
         * To take effect CTRL.RST is required.
@@ -680,7 +686,7 @@ void e1000_reset(struct e1000_adapter *adapter)
        }
 
        if (legacy_pba_adjust) {
-               if (adapter->netdev->mtu > E1000_RXBUFFER_8192)
+               if (hw->max_frame_size > E1000_RXBUFFER_8192)
                        pba -= 8; /* allocate more FIFO for Tx */
 
                if (hw->mac_type == e1000_82547) {
@@ -690,14 +696,14 @@ void e1000_reset(struct e1000_adapter *adapter)
                                (E1000_PBA_40K - pba) << E1000_PBA_BYTES_SHIFT;
                        atomic_set(&adapter->tx_fifo_stall, 0);
                }
-       } else if (hw->max_frame_size > MAXIMUM_ETHERNET_FRAME_SIZE) {
+       } else if (hw->max_frame_size >  ETH_FRAME_LEN + ETH_FCS_LEN) {
                /* adjust PBA for jumbo frames */
                ew32(PBA, pba);
 
                /* To maintain wire speed transmits, the Tx FIFO should be
-                * large enough to accomodate two full transmit packets,
+                * large enough to accommodate two full transmit packets,
                 * rounded up to the next 1KB and expressed in KB.  Likewise,
-                * the Rx FIFO should be large enough to accomodate at least
+                * the Rx FIFO should be large enough to accommodate at least
                 * one full receive packet and is similarly rounded up and
                 * expressed in KB. */
                pba = er32(PBA);
@@ -705,13 +711,17 @@ void e1000_reset(struct e1000_adapter *adapter)
                tx_space = pba >> 16;
                /* lower 16 bits has Rx packet buffer allocation size in KB */
                pba &= 0xffff;
-               /* don't include ethernet FCS because hardware appends/strips */
-               min_rx_space = adapter->netdev->mtu + ENET_HEADER_SIZE +
-                              VLAN_TAG_SIZE;
-               min_tx_space = min_rx_space;
-               min_tx_space *= 2;
+               /*
+                * the tx fifo also stores 16 bytes of information about the tx
+                * but don't include ethernet FCS because hardware appends it
+                */
+               min_tx_space = (hw->max_frame_size +
+                               sizeof(struct e1000_tx_desc) -
+                               ETH_FCS_LEN) * 2;
                min_tx_space = ALIGN(min_tx_space, 1024);
                min_tx_space >>= 10;
+               /* software strips receive CRC, so leave room for it */
+               min_rx_space = hw->max_frame_size;
                min_rx_space = ALIGN(min_rx_space, 1024);
                min_rx_space >>= 10;
 
@@ -748,23 +758,22 @@ void e1000_reset(struct e1000_adapter *adapter)
 
        ew32(PBA, pba);
 
-       /* flow control settings */
-       /* Set the FC high water mark to 90% of the FIFO size.
-        * Required to clear last 3 LSB */
-       fc_high_water_mark = ((pba * 9216)/10) & 0xFFF8;
-       /* We can't use 90% on small FIFOs because the remainder
-        * would be less than 1 full frame.  In this case, we size
-        * it to allow at least a full frame above the high water
-        *  mark. */
-       if (pba < E1000_PBA_16K)
-               fc_high_water_mark = (pba * 1024) - 1600;
-
-       hw->fc_high_water = fc_high_water_mark;
-       hw->fc_low_water = fc_high_water_mark - 8;
-       if (hw->mac_type == e1000_80003es2lan)
-               hw->fc_pause_time = 0xFFFF;
-       else
-               hw->fc_pause_time = E1000_FC_PAUSE_TIME;
+       /*
+        * flow control settings:
+        * The high water mark must be low enough to fit one full frame
+        * (or the size used for early receive) above it in the Rx FIFO.
+        * Set it to the lower of:
+        * - 90% of the Rx FIFO size, and
+        * - the full Rx FIFO size minus the early receive size (for parts
+        *   with ERT support assuming ERT set to E1000_ERT_2048), or
+        * - the full Rx FIFO size minus one full frame
+        */
+       hwm = min(((pba << 10) * 9 / 10),
+                 ((pba << 10) - hw->max_frame_size));
+
+       hw->fc_high_water = hwm & 0xFFF8;       /* 8-byte granularity */
+       hw->fc_low_water = hw->fc_high_water - 8;
+       hw->fc_pause_time = E1000_FC_PAUSE_TIME;
        hw->fc_send_xon = 1;
        hw->fc = hw->original_fc;
 
@@ -1862,6 +1871,7 @@ setup_rx_desc_die:
 
        rxdr->next_to_clean = 0;
        rxdr->next_to_use = 0;
+       rxdr->rx_skb_top = NULL;
 
        return 0;
 }
@@ -1968,10 +1978,17 @@ static void e1000_configure_rx(struct e1000_adapter *adapter)
        struct e1000_hw *hw = &adapter->hw;
        u32 rdlen, rctl, rxcsum, ctrl_ext;
 
-       rdlen = adapter->rx_ring[0].count *
-               sizeof(struct e1000_rx_desc);
-       adapter->clean_rx = e1000_clean_rx_irq;
-       adapter->alloc_rx_buf = e1000_alloc_rx_buffers;
+       if (adapter->netdev->mtu > ETH_DATA_LEN) {
+               rdlen = adapter->rx_ring[0].count *
+                       sizeof(struct e1000_rx_desc);
+               adapter->clean_rx = e1000_clean_jumbo_rx_irq;
+               adapter->alloc_rx_buf = e1000_alloc_jumbo_rx_buffers;
+       } else {
+               rdlen = adapter->rx_ring[0].count *
+                       sizeof(struct e1000_rx_desc);
+               adapter->clean_rx = e1000_clean_rx_irq;
+               adapter->alloc_rx_buf = e1000_alloc_rx_buffers;
+       }
 
        /* disable receives while setting up the descriptors */
        rctl = er32(RCTL);
@@ -2185,26 +2202,39 @@ static void e1000_clean_rx_ring(struct e1000_adapter *adapter,
        /* Free all the Rx ring sk_buffs */
        for (i = 0; i < rx_ring->count; i++) {
                buffer_info = &rx_ring->buffer_info[i];
-               if (buffer_info->dma) {
-                       pci_unmap_single(pdev,
-                                        buffer_info->dma,
-                                        buffer_info->length,
-                                        PCI_DMA_FROMDEVICE);
+               if (buffer_info->dma &&
+                   adapter->clean_rx == e1000_clean_rx_irq) {
+                       pci_unmap_single(pdev, buffer_info->dma,
+                                        buffer_info->length,
+                                        PCI_DMA_FROMDEVICE);
+               } else if (buffer_info->dma &&
+                          adapter->clean_rx == e1000_clean_jumbo_rx_irq) {
+                       pci_unmap_page(pdev, buffer_info->dma,
+                                      buffer_info->length,
+                                      PCI_DMA_FROMDEVICE);
                }
 
                buffer_info->dma = 0;
-
+               if (buffer_info->page) {
+                       put_page(buffer_info->page);
+                       buffer_info->page = NULL;
+               }
                if (buffer_info->skb) {
                        dev_kfree_skb(buffer_info->skb);
                        buffer_info->skb = NULL;
                }
        }
 
+       /* there also may be some cached data from a chained receive */
+       if (rx_ring->rx_skb_top) {
+               dev_kfree_skb(rx_ring->rx_skb_top);
+               rx_ring->rx_skb_top = NULL;
+       }
+
        size = sizeof(struct e1000_buffer) * rx_ring->count;
        memset(rx_ring->buffer_info, 0, size);
 
        /* Zero out the descriptor ring */
-
        memset(rx_ring->desc, 0, rx_ring->size);
 
        rx_ring->next_to_clean = 0;
@@ -3450,7 +3480,7 @@ static int e1000_change_mtu(struct net_device *netdev, int new_mtu)
        switch (hw->mac_type) {
        case e1000_undefined ... e1000_82542_rev2_1:
        case e1000_ich8lan:
-               if (max_frame > MAXIMUM_ETHERNET_FRAME_SIZE) {
+               if (max_frame > (ETH_FRAME_LEN + ETH_FCS_LEN)) {
                        DPRINTK(PROBE, ERR, "Jumbo Frames not supported.\n");
                        return -EINVAL;
                }
@@ -3463,7 +3493,7 @@ static int e1000_change_mtu(struct net_device *netdev, int new_mtu)
                                  &eeprom_data);
                if ((hw->device_id != E1000_DEV_ID_82573L) ||
                    (eeprom_data & EEPROM_WORD1A_ASPM_MASK)) {
-                       if (max_frame > MAXIMUM_ETHERNET_FRAME_SIZE) {
+                       if (max_frame > (ETH_FRAME_LEN + ETH_FCS_LEN)) {
                                DPRINTK(PROBE, ERR,
                                        "Jumbo Frames not supported.\n");
                                return -EINVAL;
@@ -3489,8 +3519,10 @@ static int e1000_change_mtu(struct net_device *netdev, int new_mtu)
 
        /* NOTE: netdev_alloc_skb reserves 16 bytes, and typically NET_IP_ALIGN
         * means we reserve 2 more, this pushes us to allocate from the next
-        * larger slab size
-        * i.e. RXBUFFER_2048 --> size-4096 slab */
+        * larger slab size.
+        * i.e. RXBUFFER_2048 --> size-4096 slab
+        *  however with the new *_jumbo_rx* routines, jumbo receives will use
+        *  fragmented skbs */
 
        if (max_frame <= E1000_RXBUFFER_256)
                adapter->rx_buffer_len = E1000_RXBUFFER_256;
@@ -3500,16 +3532,16 @@ static int e1000_change_mtu(struct net_device *netdev, int new_mtu)
                adapter->rx_buffer_len = E1000_RXBUFFER_1024;
        else if (max_frame <= E1000_RXBUFFER_2048)
                adapter->rx_buffer_len = E1000_RXBUFFER_2048;
-       else if (max_frame <= E1000_RXBUFFER_4096)
-               adapter->rx_buffer_len = E1000_RXBUFFER_4096;
-       else if (max_frame <= E1000_RXBUFFER_8192)
-               adapter->rx_buffer_len = E1000_RXBUFFER_8192;
-       else if (max_frame <= E1000_RXBUFFER_16384)
+       else
+#if (PAGE_SIZE >= E1000_RXBUFFER_16384)
                adapter->rx_buffer_len = E1000_RXBUFFER_16384;
+#elif (PAGE_SIZE >= E1000_RXBUFFER_4096)
+               adapter->rx_buffer_len = PAGE_SIZE;
+#endif
 
        /* adjust allocation if LPE protects us, and we aren't using SBP */
        if (!hw->tbi_compatibility_on &&
-           ((max_frame == MAXIMUM_ETHERNET_FRAME_SIZE) ||
+           ((max_frame == (ETH_FRAME_LEN + ETH_FCS_LEN)) ||
             (max_frame == MAXIMUM_ETHERNET_VLAN_SIZE)))
                adapter->rx_buffer_len = MAXIMUM_ETHERNET_VLAN_SIZE;
 
@@ -3987,9 +4019,227 @@ static void e1000_rx_checksum(struct e1000_adapter *adapter, u32 status_err,
 }
 
 /**
+ * e1000_consume_page - helper function
+ **/
+static void e1000_consume_page(struct e1000_buffer *bi, struct sk_buff *skb,
+                               u16 length)
+{
+       bi->page = NULL;
+       skb->len += length;
+       skb->data_len += length;
+       skb->truesize += length;
+}
+
+/**
+ * e1000_receive_skb - helper function to handle rx indications
+ * @adapter: board private structure
+ * @status: descriptor status field as written by hardware
+ * @vlan: descriptor vlan field as written by hardware (no le/be conversion)
+ * @skb: pointer to sk_buff to be indicated to stack
+ */
+static void e1000_receive_skb(struct e1000_adapter *adapter, u8 status,
+                             __le16 vlan, struct sk_buff *skb)
+{
+       if (unlikely(adapter->vlgrp && (status & E1000_RXD_STAT_VP))) {
+               vlan_hwaccel_receive_skb(skb, adapter->vlgrp,
+                                        le16_to_cpu(vlan) &
+                                        E1000_RXD_SPC_VLAN_MASK);
+       } else {
+               netif_receive_skb(skb);
+       }
+}
+
+/**
+ * e1000_clean_jumbo_rx_irq - Send received data up the network stack; legacy
+ * @adapter: board private structure
+ * @rx_ring: ring to clean
+ * @work_done: amount of napi work completed this call
+ * @work_to_do: max amount of work allowed for this call to do
+ *
+ * the return value indicates whether actual cleaning was done, there
+ * is no guarantee that everything was cleaned
+ */
+static bool e1000_clean_jumbo_rx_irq(struct e1000_adapter *adapter,
+                                    struct e1000_rx_ring *rx_ring,
+                                    int *work_done, int work_to_do)
+{
+       struct e1000_hw *hw = &adapter->hw;
+       struct net_device *netdev = adapter->netdev;
+       struct pci_dev *pdev = adapter->pdev;
+       struct e1000_rx_desc *rx_desc, *next_rxd;
+       struct e1000_buffer *buffer_info, *next_buffer;
+       unsigned long irq_flags;
+       u32 length;
+       unsigned int i;
+       int cleaned_count = 0;
+       bool cleaned = false;
+       unsigned int total_rx_bytes=0, total_rx_packets=0;
+
+       i = rx_ring->next_to_clean;
+       rx_desc = E1000_RX_DESC(*rx_ring, i);
+       buffer_info = &rx_ring->buffer_info[i];
+
+       while (rx_desc->status & E1000_RXD_STAT_DD) {
+               struct sk_buff *skb;
+               u8 status;
+
+               if (*work_done >= work_to_do)
+                       break;
+               (*work_done)++;
+
+               status = rx_desc->status;
+               skb = buffer_info->skb;
+               buffer_info->skb = NULL;
+
+               if (++i == rx_ring->count) i = 0;
+               next_rxd = E1000_RX_DESC(*rx_ring, i);
+               prefetch(next_rxd);
+
+               next_buffer = &rx_ring->buffer_info[i];
+
+               cleaned = true;
+               cleaned_count++;
+               pci_unmap_page(pdev, buffer_info->dma, buffer_info->length,
+                              PCI_DMA_FROMDEVICE);
+               buffer_info->dma = 0;
+
+               length = le16_to_cpu(rx_desc->length);
+
+               /* errors is only valid for DD + EOP descriptors */
+               if (unlikely((status & E1000_RXD_STAT_EOP) &&
+                   (rx_desc->errors & E1000_RXD_ERR_FRAME_ERR_MASK))) {
+                       u8 last_byte = *(skb->data + length - 1);
+                       if (TBI_ACCEPT(hw, status, rx_desc->errors, length,
+                                      last_byte)) {
+                               spin_lock_irqsave(&adapter->stats_lock,
+                                                 irq_flags);
+                               e1000_tbi_adjust_stats(hw, &adapter->stats,
+                                                      length, skb->data);
+                               spin_unlock_irqrestore(&adapter->stats_lock,
+                                                      irq_flags);
+                               length--;
+                       } else {
+                               /* recycle both page and skb */
+                               buffer_info->skb = skb;
+                               /* an error means any chain goes out the window
+                                * too */
+                               if (rx_ring->rx_skb_top)
+                                       dev_kfree_skb(rx_ring->rx_skb_top);
+                               rx_ring->rx_skb_top = NULL;
+                               goto next_desc;
+                       }
+               }
+
+#define rxtop rx_ring->rx_skb_top
+               if (!(status & E1000_RXD_STAT_EOP)) {
+                       /* this descriptor is only the beginning (or middle) */
+                       if (!rxtop) {
+                               /* this is the beginning of a chain */
+                               rxtop = skb;
+                               skb_fill_page_desc(rxtop, 0, buffer_info->page,
+                                                  0, length);
+                       } else {
+                               /* this is the middle of a chain */
+                               skb_fill_page_desc(rxtop,
+                                   skb_shinfo(rxtop)->nr_frags,
+                                   buffer_info->page, 0, length);
+                               /* re-use the skb, only consumed the page */
+                               buffer_info->skb = skb;
+                       }
+                       e1000_consume_page(buffer_info, rxtop, length);
+                       goto next_desc;
+               } else {
+                       if (rxtop) {
+                               /* end of the chain */
+                               skb_fill_page_desc(rxtop,
+                                   skb_shinfo(rxtop)->nr_frags,
+                                   buffer_info->page, 0, length);
+                               /* re-use the current skb, we only consumed the
+                                * page */
+                               buffer_info->skb = skb;
+                               skb = rxtop;
+                               rxtop = NULL;
+                               e1000_consume_page(buffer_info, skb, length);
+                       } else {
+                               /* no chain, got EOP, this buf is the packet
+                                * copybreak to save the put_page/alloc_page */
+                               if (length <= copybreak &&
+                                   skb_tailroom(skb) >= length) {
+                                       u8 *vaddr;
+                                       vaddr = kmap_atomic(buffer_info->page,
+                                                           KM_SKB_DATA_SOFTIRQ);
+                                       memcpy(skb_tail_pointer(skb), vaddr, length);
+                                       kunmap_atomic(vaddr,
+                                                     KM_SKB_DATA_SOFTIRQ);
+                                       /* re-use the page, so don't erase
+                                        * buffer_info->page */
+                                       skb_put(skb, length);
+                               } else {
+                                       skb_fill_page_desc(skb, 0,
+                                                          buffer_info->page, 0,
+                                                          length);
+                                       e1000_consume_page(buffer_info, skb,
+                                                          length);
+                               }
+                       }
+               }
+
+               /* Receive Checksum Offload XXX recompute due to CRC strip? */
+               e1000_rx_checksum(adapter,
+                                 (u32)(status) |
+                                 ((u32)(rx_desc->errors) << 24),
+                                 le16_to_cpu(rx_desc->csum), skb);
+
+               pskb_trim(skb, skb->len - 4);
+
+               /* probably a little skewed due to removing CRC */
+               total_rx_bytes += skb->len;
+               total_rx_packets++;
+
+               /* eth type trans needs skb->data to point to something */
+               if (!pskb_may_pull(skb, ETH_HLEN)) {
+                       DPRINTK(DRV, ERR, "pskb_may_pull failed.\n");
+                       dev_kfree_skb(skb);
+                       goto next_desc;
+               }
+
+               skb->protocol = eth_type_trans(skb, netdev);
+
+               e1000_receive_skb(adapter, status, rx_desc->special, skb);
+
+next_desc:
+               rx_desc->status = 0;
+
+               /* return some buffers to hardware, one at a time is too slow */
+               if (unlikely(cleaned_count >= E1000_RX_BUFFER_WRITE)) {
+                       adapter->alloc_rx_buf(adapter, rx_ring, cleaned_count);
+                       cleaned_count = 0;
+               }
+
+               /* use prefetched values */
+               rx_desc = next_rxd;
+               buffer_info = next_buffer;
+       }
+       rx_ring->next_to_clean = i;
+
+       cleaned_count = E1000_DESC_UNUSED(rx_ring);
+       if (cleaned_count)
+               adapter->alloc_rx_buf(adapter, rx_ring, cleaned_count);
+
+       adapter->total_rx_packets += total_rx_packets;
+       adapter->total_rx_bytes += total_rx_bytes;
+       adapter->net_stats.rx_bytes += total_rx_bytes;
+       adapter->net_stats.rx_packets += total_rx_packets;
+       return cleaned;
+}
+
+/**
  * e1000_clean_rx_irq - Send received data up the network stack; legacy
  * @adapter: board private structure
- **/
+ * @rx_ring: ring to clean
+ * @work_done: amount of napi work completed this call
+ * @work_to_do: max amount of work allowed for this call to do
+ */
 static bool e1000_clean_rx_irq(struct e1000_adapter *adapter,
                               struct e1000_rx_ring *rx_ring,
                               int *work_done, int work_to_do)
@@ -4001,7 +4251,6 @@ static bool e1000_clean_rx_irq(struct e1000_adapter *adapter,
        struct e1000_buffer *buffer_info, *next_buffer;
        unsigned long flags;
        u32 length;
-       u8 last_byte;
        unsigned int i;
        int cleaned_count = 0;
        bool cleaned = false;
@@ -4033,9 +4282,7 @@ static bool e1000_clean_rx_irq(struct e1000_adapter *adapter,
 
                cleaned = true;
                cleaned_count++;
-               pci_unmap_single(pdev,
-                                buffer_info->dma,
-                                buffer_info->length,
+               pci_unmap_single(pdev, buffer_info->dma, buffer_info->length,
                                 PCI_DMA_FROMDEVICE);
                buffer_info->dma = 0;
 
@@ -4052,7 +4299,7 @@ static bool e1000_clean_rx_irq(struct e1000_adapter *adapter,
                }
 
                if (unlikely(rx_desc->errors & E1000_RXD_ERR_FRAME_ERR_MASK)) {
-                       last_byte = *(skb->data + length - 1);
+                       u8 last_byte = *(skb->data + length - 1);
                        if (TBI_ACCEPT(hw, status, rx_desc->errors, length,
                                       last_byte)) {
                                spin_lock_irqsave(&adapter->stats_lock, flags);
@@ -4107,13 +4354,7 @@ static bool e1000_clean_rx_irq(struct e1000_adapter *adapter,
 
                skb->protocol = eth_type_trans(skb, netdev);
 
-               if (unlikely(adapter->vlgrp &&
-                           (status & E1000_RXD_STAT_VP))) {
-                       vlan_hwaccel_receive_skb(skb, adapter->vlgrp,
-                                                le16_to_cpu(rx_desc->special));
-               } else {
-                       netif_receive_skb(skb);
-               }
+               e1000_receive_skb(adapter, status, rx_desc->special, skb);
 
 next_desc:
                rx_desc->status = 0;
@@ -4142,6 +4383,114 @@ next_desc:
 }
 
 /**
+ * e1000_alloc_jumbo_rx_buffers - Replace used jumbo receive buffers
+ * @adapter: address of board private structure
+ * @rx_ring: pointer to receive ring structure
+ * @cleaned_count: number of buffers to allocate this pass
+ **/
+
+static void
+e1000_alloc_jumbo_rx_buffers(struct e1000_adapter *adapter,
+                             struct e1000_rx_ring *rx_ring, int cleaned_count)
+{
+       struct net_device *netdev = adapter->netdev;
+       struct pci_dev *pdev = adapter->pdev;
+       struct e1000_rx_desc *rx_desc;
+       struct e1000_buffer *buffer_info;
+       struct sk_buff *skb;
+       unsigned int i;
+       unsigned int bufsz = 256 -
+                            16 /*for skb_reserve */ -
+                            NET_IP_ALIGN;
+
+       i = rx_ring->next_to_use;
+       buffer_info = &rx_ring->buffer_info[i];
+
+       while (cleaned_count--) {
+               skb = buffer_info->skb;
+               if (skb) {
+                       skb_trim(skb, 0);
+                       goto check_page;
+               }
+
+               skb = netdev_alloc_skb(netdev, bufsz);
+               if (unlikely(!skb)) {
+                       /* Better luck next round */
+                       adapter->alloc_rx_buff_failed++;
+                       break;
+               }
+
+               /* Fix for errata 23, can't cross 64kB boundary */
+               if (!e1000_check_64k_bound(adapter, skb->data, bufsz)) {
+                       struct sk_buff *oldskb = skb;
+                       DPRINTK(PROBE, ERR, "skb align check failed: %u bytes "
+                                            "at %p\n", bufsz, skb->data);
+                       /* Try again, without freeing the previous */
+                       skb = netdev_alloc_skb(netdev, bufsz);
+                       /* Failed allocation, critical failure */
+                       if (!skb) {
+                               dev_kfree_skb(oldskb);
+                               adapter->alloc_rx_buff_failed++;
+                               break;
+                       }
+
+                       if (!e1000_check_64k_bound(adapter, skb->data, bufsz)) {
+                               /* give up */
+                               dev_kfree_skb(skb);
+                               dev_kfree_skb(oldskb);
+                               break; /* while (cleaned_count--) */
+                       }
+
+                       /* Use new allocation */
+                       dev_kfree_skb(oldskb);
+               }
+               /* 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
+                */
+               skb_reserve(skb, NET_IP_ALIGN);
+
+               buffer_info->skb = skb;
+               buffer_info->length = adapter->rx_buffer_len;
+check_page:
+               /* allocate a new page if necessary */
+               if (!buffer_info->page) {
+                       buffer_info->page = alloc_page(GFP_ATOMIC);
+                       if (unlikely(!buffer_info->page)) {
+                               adapter->alloc_rx_buff_failed++;
+                               break;
+                       }
+               }
+
+               if (!buffer_info->dma)
+                       buffer_info->dma = pci_map_page(pdev,
+                                                       buffer_info->page, 0,
+                                                       buffer_info->length,
+                                                       PCI_DMA_FROMDEVICE);
+
+               rx_desc = E1000_RX_DESC(*rx_ring, i);
+               rx_desc->buffer_addr = cpu_to_le64(buffer_info->dma);
+
+               if (unlikely(++i == rx_ring->count))
+                       i = 0;
+               buffer_info = &rx_ring->buffer_info[i];
+       }
+
+       if (likely(rx_ring->next_to_use != i)) {
+               rx_ring->next_to_use = i;
+               if (unlikely(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->rdt);
+       }
+}
+
+/**
  * e1000_alloc_rx_buffers - Replace used receive buffers; legacy & extended
  * @adapter: address of board private structure
  **/
@@ -4186,6 +4535,7 @@ static void e1000_alloc_rx_buffers(struct e1000_adapter *adapter,
                        /* Failed allocation, critical failure */
                        if (!skb) {
                                dev_kfree_skb(oldskb);
+                               adapter->alloc_rx_buff_failed++;
                                break;
                        }
 
@@ -4193,6 +4543,7 @@ static void e1000_alloc_rx_buffers(struct e1000_adapter *adapter,
                                /* give up */
                                dev_kfree_skb(skb);
                                dev_kfree_skb(oldskb);
+                               adapter->alloc_rx_buff_failed++;
                                break; /* while !buffer_info->skb */
                        }
 
@@ -4210,9 +4561,14 @@ static void e1000_alloc_rx_buffers(struct e1000_adapter *adapter,
 map_skb:
                buffer_info->dma = pci_map_single(pdev,
                                                  skb->data,
-                                                 adapter->rx_buffer_len,
+                                                 buffer_info->length,
                                                  PCI_DMA_FROMDEVICE);
 
+               /*
+                * XXX if it was allocated cleanly it will never map to a
+                * boundary crossing
+                */
+
                /* Fix for errata 23, can't cross 64kB boundary */
                if (!e1000_check_64k_bound(adapter,
                                        (void *)(unsigned long)buffer_info->dma,
@@ -4229,6 +4585,7 @@ map_skb:
                                         PCI_DMA_FROMDEVICE);
                        buffer_info->dma = 0;
 
+                       adapter->alloc_rx_buff_failed++;
                        break; /* while !buffer_info->skb */
                }
                rx_desc = E1000_RX_DESC(*rx_ring, i);
index cc2ab64..71605d6 100644 (file)
@@ -1145,7 +1145,7 @@ static int eepro_send_packet(struct sk_buff *skb, struct net_device *dev)
 
        if (length < ETH_ZLEN) {
                if (skb_padto(skb, ETH_ZLEN))
-                       return 0;
+                       return NETDEV_TX_OK;
                length = ETH_ZLEN;
        }
        netif_stop_queue (dev);
@@ -1178,7 +1178,7 @@ static int eepro_send_packet(struct sk_buff *skb, struct net_device *dev)
        eepro_en_int(ioaddr);
        spin_unlock_irqrestore(&lp->lock, flags);
 
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 
index 1686dca..8c44ef4 100644 (file)
@@ -664,7 +664,7 @@ static int eexp_xmit(struct sk_buff *buf, struct net_device *dev)
 
        if (buf->len < ETH_ZLEN) {
                if (skb_padto(buf, ETH_ZLEN))
-                       return 0;
+                       return NETDEV_TX_OK;
                length = ETH_ZLEN;
        }
 
@@ -691,7 +691,7 @@ static int eexp_xmit(struct sk_buff *buf, struct net_device *dev)
        spin_unlock_irqrestore(&lp->lock, flags);
 #endif
        enable_irq(dev->irq);
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 /*
index fc6cc03..372d6c6 100644 (file)
@@ -1299,7 +1299,7 @@ static int enc28j60_send_packet(struct sk_buff *skb, struct net_device *dev)
        priv->tx_skb = skb;
        schedule_work(&priv->tx_work);
 
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 static void enc28j60_tx_work_handler(struct work_struct *work)
index b60e27d..d6a7aa3 100644 (file)
@@ -970,7 +970,7 @@ static int epic_start_xmit(struct sk_buff *skb, struct net_device *dev)
        unsigned long flags;
 
        if (skb_padto(skb, ETH_ZLEN))
-               return 0;
+               return NETDEV_TX_OK;
 
        /* Caution: the write order is important here, set the field with the
           "ownership" bit last. */
@@ -1014,7 +1014,7 @@ static int epic_start_xmit(struct sk_buff *skb, struct net_device *dev)
                           dev->name, (int)skb->len, entry, ctrl_word,
                           (int)inl(dev->base_addr + TxSTAT));
 
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 static void epic_tx_error(struct net_device *dev, struct epic_private *ep,
index 19b7dd9..c0e69c5 100644 (file)
@@ -348,7 +348,7 @@ static int eql_slave_xmit(struct sk_buff *skb, struct net_device *dev)
 
        spin_unlock(&eql->queue.lock);
 
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 /*
index 0d8b6da..97d5205 100644 (file)
@@ -1064,7 +1064,7 @@ static int eth16i_tx(struct sk_buff *skb, struct net_device *dev)
 
        if (length < ETH_ZLEN) {
                if (skb_padto(skb, ETH_ZLEN))
-                       return 0;
+                       return NETDEV_TX_OK;
                length = ETH_ZLEN;
        }
        buf = skb->data;
@@ -1126,7 +1126,7 @@ static int eth16i_tx(struct sk_buff *skb, struct net_device *dev)
        /* outb(TX_INTR_DONE | TX_INTR_16_COL, ioaddr + TX_INTR_REG); */
        status = 0;
        dev_kfree_skb(skb);
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 static void eth16i_rx(struct net_device *dev)
index 1e97232..9c51bc8 100644 (file)
@@ -868,7 +868,7 @@ static int ewrk3_queue_pkt (struct sk_buff *skb, struct net_device *dev)
        if (inb (EWRK3_FMQC) == 0)
                netif_stop_queue (dev);
 
-       return 0;
+       return NETDEV_TX_OK;
 
 err_out:
        ENABLE_IRQs;
index 891be28..75e5fe5 100644 (file)
@@ -1374,7 +1374,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev)
        dev->trans_start = jiffies;
 
        spin_unlock_irqrestore(&np->lock, flags);
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 
index d4b9807..e3d99fe 100644 (file)
@@ -366,7 +366,7 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
        spin_unlock_irqrestore(&fep->hw_lock, flags);
 
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 static void
index 75a0999..a2d69c1 100644 (file)
@@ -36,6 +36,7 @@
 #include <asm/pgtable.h>
 #include <asm/irq.h>
 #include <asm/uaccess.h>
+#include <asm/mpc5xxx.h>
 
 #include "fs_enet.h"
 #include "fec.h"
@@ -103,11 +104,11 @@ static int fs_enet_fec_mii_reset(struct mii_bus *bus)
 static int __devinit fs_enet_mdio_probe(struct of_device *ofdev,
                                         const struct of_device_id *match)
 {
-       struct device_node *np = NULL;
        struct resource res;
        struct mii_bus *new_bus;
        struct fec_info *fec;
-       int ret = -ENOMEM, i;
+       int (*get_bus_freq)(struct device_node *) = match->data;
+       int ret = -ENOMEM, clock, speed;
 
        new_bus = mdiobus_alloc();
        if (!new_bus)
@@ -133,13 +134,35 @@ static int __devinit fs_enet_mdio_probe(struct of_device *ofdev,
        if (!fec->fecp)
                goto out_fec;
 
-       fec->mii_speed = ((ppc_proc_freq + 4999999) / 5000000) << 1;
+       if (get_bus_freq) {
+               clock = get_bus_freq(ofdev->node);
+               if (!clock) {
+                       /* Use maximum divider if clock is unknown */
+                       dev_warn(&ofdev->dev, "could not determine IPS clock\n");
+                       clock = 0x3F * 5000000;
+               }
+       } else
+               clock = ppc_proc_freq;
+
+       /*
+        * Scale for a MII clock <= 2.5 MHz
+        * Note that only 6 bits (25:30) are available for MII speed.
+        */
+       speed = (clock + 4999999) / 5000000;
+       if (speed > 0x3F) {
+               speed = 0x3F;
+               dev_err(&ofdev->dev,
+                       "MII clock (%d Hz) exceeds max (2.5 MHz)\n",
+                       clock / speed);
+       }
+
+       fec->mii_speed = speed << 1;
 
        setbits32(&fec->fecp->fec_r_cntrl, FEC_RCNTRL_MII_MODE);
        setbits32(&fec->fecp->fec_ecntrl, FEC_ECNTRL_PINMUX |
                                          FEC_ECNTRL_ETHER_EN);
        out_be32(&fec->fecp->fec_ievent, FEC_ENET_MII);
-       out_be32(&fec->fecp->fec_mii_speed, fec->mii_speed);
+       clrsetbits_be32(&fec->fecp->fec_mii_speed, 0x7E, fec->mii_speed);
 
        new_bus->phy_mask = ~0;
        new_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL);
@@ -188,6 +211,12 @@ static struct of_device_id fs_enet_mdio_fec_match[] = {
        {
                .compatible = "fsl,pq1-fec-mdio",
        },
+#if defined(CONFIG_PPC_MPC512x)
+       {
+               .compatible = "fsl,mpc5121-fec-mdio",
+               .data = mpc5xxx_get_bus_frequency,
+       },
+#endif
        {},
 };
 
index f8ffcbf..056ba46 100644 (file)
@@ -297,7 +297,6 @@ static int gfar_probe(struct of_device *ofdev,
        u32 tempval;
        struct net_device *dev = NULL;
        struct gfar_private *priv = NULL;
-       DECLARE_MAC_BUF(mac);
        int err = 0;
        int len_devname;
 
index 9d5b62c..4e8d372 100644 (file)
@@ -1369,7 +1369,7 @@ static int hamachi_start_xmit(struct sk_buff *skb, struct net_device *dev)
                printk(KERN_DEBUG "%s: Hamachi transmit frame #%d queued in slot %d.\n",
                           dev->name, hmp->cur_tx, entry);
        }
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 /* The interrupt handler does all of the Rx thread work and cleans up
index 981ab53..6cb2bdf 100644 (file)
@@ -255,7 +255,7 @@ static int sp_xmit(struct sk_buff *skb, struct net_device *dev)
 
        dev_kfree_skb(skb);
 
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 static int sp_open_dev(struct net_device *dev)
index 5e4b7af..e229edf 100644 (file)
@@ -774,18 +774,18 @@ static int baycom_send_packet(struct sk_buff *skb, struct net_device *dev)
        if (skb->data[0] != 0) {
                do_kiss_params(bc, skb->data, skb->len);
                dev_kfree_skb(skb);
-               return 0;
+               return NETDEV_TX_OK;
        }
        if (bc->skb)
                return NETDEV_TX_LOCKED;
        /* strip KISS byte */
        if (skb->len >= HDLCDRV_MAXFLEN+1 || skb->len < 3) {
                dev_kfree_skb(skb);
-               return 0;
+               return NETDEV_TX_OK;
        }
        netif_stop_queue(dev);
        bc->skb = skb;
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 /* --------------------------------------------------------------------- */
index abcd19a..4c5f4df 100644 (file)
@@ -305,7 +305,7 @@ static int bpq_xmit(struct sk_buff *skb, struct net_device *dev)
   
        dev_queue_xmit(skb);
        netif_wake_queue(dev);
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 /*
index 7459b3a..950f3bb 100644 (file)
@@ -959,7 +959,7 @@ static int scc_send_packet(struct sk_buff *skb, struct net_device *dev)
        spin_unlock_irqrestore(&priv->ring_lock, flags);
        dev_kfree_skb(skb);
 
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 
index d034f8c..16b060b 100644 (file)
@@ -406,13 +406,13 @@ static int hdlcdrv_send_packet(struct sk_buff *skb, struct net_device *dev)
        if (skb->data[0] != 0) {
                do_kiss_params(sm, skb->data, skb->len);
                dev_kfree_skb(skb);
-               return 0;
+               return NETDEV_TX_OK;
        }
        if (sm->skb)
                return NETDEV_TX_LOCKED;
        netif_stop_queue(dev);
        sm->skb = skb;
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 /* --------------------------------------------------------------------- */
index fda2fc8..ac191ef 100644 (file)
@@ -560,7 +560,7 @@ static int ax_xmit(struct sk_buff *skb, struct net_device *dev)
                kfree_skb(skb);
        }
 
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 static int ax_open_dev(struct net_device *dev)
index d712e7a..c540652 100644 (file)
@@ -1643,7 +1643,7 @@ static int scc_net_tx(struct sk_buff *skb, struct net_device *dev)
        if (skb->len > scc->stat.bufsize || skb->len < 2) {
                scc->dev_stat.tx_dropped++;     /* bogus frame */
                dev_kfree_skb(skb);
-               return 0;
+               return NETDEV_TX_OK;
        }
        
        scc->dev_stat.tx_packets++;
@@ -1656,7 +1656,7 @@ static int scc_net_tx(struct sk_buff *skb, struct net_device *dev)
        if (kisscmd) {
                scc_set_param(scc, kisscmd, *skb->data);
                dev_kfree_skb(skb);
-               return 0;
+               return NETDEV_TX_OK;
        }
 
        spin_lock_irqsave(&scc->lock, flags);
@@ -1684,7 +1684,7 @@ static int scc_net_tx(struct sk_buff *skb, struct net_device *dev)
                        __scc_start_tx_timer(scc, t_dwait, 0);
        }
        spin_unlock_irqrestore(&scc->lock, flags);
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 /* ----> ioctl functions <---- */
index b066919..b85aa16 100644 (file)
@@ -600,7 +600,7 @@ static int yam_send_packet(struct sk_buff *skb, struct net_device *dev)
 
        skb_queue_tail(&yp->send_queue, skb);
        dev->trans_start = jiffies;
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 static void yam_start_tx(struct net_device *dev, struct yam_port *yp)
index 1d3429a..d1b6338 100644 (file)
@@ -1499,7 +1499,7 @@ static int hp100_start_xmit_bm(struct sk_buff *skb, struct net_device *dev)
                goto drop;
 
        if (lp->chip == HP100_CHIPID_SHASTA && skb_padto(skb, ETH_ZLEN))
-               return 0;
+               return NETDEV_TX_OK;
 
        /* Get Tx ring tail pointer */
        if (lp->txrtail->next == lp->txrhead) {
@@ -1585,7 +1585,7 @@ static int hp100_start_xmit_bm(struct sk_buff *skb, struct net_device *dev)
        lp->stats.tx_bytes += skb->len;
        dev->trans_start = jiffies;
 
-       return 0;
+       return NETDEV_TX_OK;
 
 drop:
        dev_kfree_skb(skb);
@@ -1752,7 +1752,7 @@ static int hp100_start_xmit(struct sk_buff *skb, struct net_device *dev)
        printk("hp100: %s: start_xmit: end\n", dev->name);
 #endif
 
-       return 0;
+       return NETDEV_TX_OK;
 
 drop:
        dev_kfree_skb(skb);
index beb8421..5443558 100644 (file)
@@ -1342,7 +1342,7 @@ static inline int emac_xmit_finish(struct emac_instance *dev, int len)
        ++dev->stats.tx_packets;
        dev->stats.tx_bytes += len;
 
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 /* Tx lock BH */
index 0995c43..76b295a 100644 (file)
@@ -971,7 +971,7 @@ out:        spin_lock_irqsave(&adapter->stats_lock, flags);
        spin_unlock_irqrestore(&adapter->stats_lock, flags);
 
        dev_kfree_skb(skb);
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 static int ibmveth_poll(struct napi_struct *napi, int budget)
index 96713ef..0a79b45 100644 (file)
@@ -164,7 +164,7 @@ static int ifb_xmit(struct sk_buff *skb, struct net_device *dev)
 {
        struct ifb_private *dp = netdev_priv(dev);
        struct net_device_stats *stats = &dev->stats;
-       int ret = 0;
+       int ret = NETDEV_TX_OK;
        u32 from = G_TC_FROM(skb->tc_verd);
 
        stats->rx_packets++;
index e3cfefa..8ec15ab 100644 (file)
@@ -1515,7 +1515,7 @@ static int ioc3_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
        spin_unlock_irq(&ip->ioc3_lock);
 
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 static void ioc3_timeout(struct net_device *dev)
index ad17955..f0d0cea 100644 (file)
@@ -1466,7 +1466,7 @@ static int ali_ircc_fir_hard_xmit(struct sk_buff *skb, struct net_device *dev)
                        dev->trans_start = jiffies;
                        spin_unlock_irqrestore(&self->lock, flags);
                        dev_kfree_skb(skb);
-                       return 0;
+                       return NETDEV_TX_OK;
                } else
                        self->new_speed = speed;
        }
@@ -1577,7 +1577,7 @@ static int ali_ircc_fir_hard_xmit(struct sk_buff *skb, struct net_device *dev)
        dev_kfree_skb(skb);
 
        IRDA_DEBUG(1, "%s(), ----------------- End ------------------\n", __func__ );
-       return 0;       
+       return NETDEV_TX_OK;    
 }
 
 
@@ -1966,10 +1966,10 @@ static int ali_ircc_sir_hard_xmit(struct sk_buff *skb, struct net_device *dev)
        
        IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __func__ );
        
-       IRDA_ASSERT(dev != NULL, return 0;);
+       IRDA_ASSERT(dev != NULL, return NETDEV_TX_OK;);
        
        self = netdev_priv(dev);
-       IRDA_ASSERT(self != NULL, return 0;);
+       IRDA_ASSERT(self != NULL, return NETDEV_TX_OK;);
 
        iobase = self->io.sir_base;
 
@@ -1991,7 +1991,7 @@ static int ali_ircc_sir_hard_xmit(struct sk_buff *skb, struct net_device *dev)
                        dev->trans_start = jiffies;
                        spin_unlock_irqrestore(&self->lock, flags);
                        dev_kfree_skb(skb);
-                       return 0;
+                       return NETDEV_TX_OK;
                } else
                        self->new_speed = speed;
        }
@@ -2015,7 +2015,7 @@ static int ali_ircc_sir_hard_xmit(struct sk_buff *skb, struct net_device *dev)
        
        IRDA_DEBUG(2, "%s(), ----------------- End ------------------\n", __func__ );
        
-       return 0;       
+       return NETDEV_TX_OK;    
 }
 
 
index c4361d4..22baf65 100644 (file)
@@ -502,7 +502,7 @@ static int au1k_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev)
                        aup->newspeed = 0;
                }
                dev_kfree_skb(skb);
-               return 0;
+               return NETDEV_TX_OK;
        }
 
        ptxd = aup->tx_ring[aup->tx_head];
@@ -555,7 +555,7 @@ static int au1k_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev)
        dev_kfree_skb(skb);
        aup->tx_head = (aup->tx_head + 1) & (NUM_IR_DESC - 1);
        dev->trans_start = jiffies;
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 
index 9a0346e..e4e9056 100644 (file)
@@ -981,7 +981,7 @@ toshoboe_hard_xmit (struct sk_buff *skb, struct net_device *dev)
 
   self = netdev_priv(dev);
 
-  IRDA_ASSERT (self != NULL, return 0; );
+  IRDA_ASSERT (self != NULL, return NETDEV_TX_OK; );
 
   IRDA_DEBUG (1, "%s.tx:%x(%x)%x\n", __func__
       ,skb->len,self->txpending,INB (OBOE_ENABLEH));
@@ -1021,7 +1021,7 @@ toshoboe_hard_xmit (struct sk_buff *skb, struct net_device *dev)
             {
              spin_unlock_irqrestore(&self->spinlock, flags);
               dev_kfree_skb (skb);
-              return 0;
+              return NETDEV_TX_OK;
             }
           /* True packet, go on, but */
           /* do not accept anything before change speed execution */
@@ -1036,7 +1036,7 @@ toshoboe_hard_xmit (struct sk_buff *skb, struct net_device *dev)
           toshoboe_setbaud (self);
          spin_unlock_irqrestore(&self->spinlock, flags);
           dev_kfree_skb (skb);
-          return 0;
+          return NETDEV_TX_OK;
         }
 
     }
@@ -1143,7 +1143,7 @@ dumpbufs(skb->data,skb->len,'>');
   spin_unlock_irqrestore(&self->spinlock, flags);
   dev_kfree_skb (skb);
 
-  return 0;
+  return NETDEV_TX_OK;
 }
 
 /*interrupt handler */
index 0c0831c..6a1aa7a 100644 (file)
@@ -534,7 +534,7 @@ static int irda_usb_hard_xmit(struct sk_buff *skb, struct net_device *netdev)
        }
        spin_unlock_irqrestore(&self->lock, flags);
        
-       return 0;
+       return NETDEV_TX_OK;
 
 drop:
        /* Drop silently the skb and exit */
index 45fd9c1..51ca89c 100644 (file)
@@ -1365,7 +1365,7 @@ static int nsc_ircc_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev)
        
        self = netdev_priv(dev);
 
-       IRDA_ASSERT(self != NULL, return 0;);
+       IRDA_ASSERT(self != NULL, return NETDEV_TX_OK;);
 
        iobase = self->io.fir_base;
 
@@ -1397,7 +1397,7 @@ static int nsc_ircc_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev)
                        dev->trans_start = jiffies;
                        spin_unlock_irqrestore(&self->lock, flags);
                        dev_kfree_skb(skb);
-                       return 0;
+                       return NETDEV_TX_OK;
                } else
                        self->new_speed = speed;
        }
@@ -1424,7 +1424,7 @@ static int nsc_ircc_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev)
 
        dev_kfree_skb(skb);
 
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 static int nsc_ircc_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev)
@@ -1467,7 +1467,7 @@ static int nsc_ircc_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev)
                        dev->trans_start = jiffies;
                        spin_unlock_irqrestore(&self->lock, flags);
                        dev_kfree_skb(skb);
-                       return 0;
+                       return NETDEV_TX_OK;
                } else {
                        /* Change speed after current frame */
                        self->new_speed = speed;
@@ -1554,7 +1554,7 @@ static int nsc_ircc_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev)
        spin_unlock_irqrestore(&self->lock, flags);
        dev_kfree_skb(skb);
 
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 /*
index 3376a4f..e76a083 100644 (file)
@@ -504,7 +504,7 @@ static int pxa_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev)
                        pxa_irda_set_speed(si, speed);
                }
                dev_kfree_skb(skb);
-               return 0;
+               return NETDEV_TX_OK;
        }
 
        netif_stop_queue(dev);
@@ -539,7 +539,7 @@ static int pxa_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev)
 
        dev_kfree_skb(skb);
        dev->trans_start = jiffies;
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 static int pxa_irda_ioctl(struct net_device *dev, struct ifreq *ifreq, int cmd)
index 2aeb2e6..70e6acc 100644 (file)
@@ -667,7 +667,7 @@ static int sa1100_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev)
                        sa1100_irda_set_speed(si, speed);
                }
                dev_kfree_skb(skb);
-               return 0;
+               return NETDEV_TX_OK;
        }
 
        if (!IS_FIR(si)) {
@@ -715,7 +715,7 @@ static int sa1100_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev)
 
        dev->trans_start = jiffies;
 
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 static int
index fd0796c..71dce20 100644 (file)
@@ -590,7 +590,7 @@ static int sirdev_hard_xmit(struct sk_buff *skb, struct net_device *ndev)
        int err;
        s32 speed;
 
-       IRDA_ASSERT(dev != NULL, return 0;);
+       IRDA_ASSERT(dev != NULL, return NETDEV_TX_OK;);
 
        netif_stop_queue(ndev);
 
@@ -621,7 +621,7 @@ static int sirdev_hard_xmit(struct sk_buff *skb, struct net_device *ndev)
                         */
 
                        dev_kfree_skb_any(skb);
-                       return 0;
+                       return NETDEV_TX_OK;
                } else
                        dev->new_speed = speed;
        }
@@ -668,7 +668,7 @@ static int sirdev_hard_xmit(struct sk_buff *skb, struct net_device *ndev)
        }
        spin_unlock_irqrestore(&dev->tx_lock, flags);
 
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 /* called from network layer with rtnl hold */
index d0797ad..15f8a7f 100644 (file)
@@ -886,10 +886,10 @@ static int smsc_ircc_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev)
 
        IRDA_DEBUG(1, "%s\n", __func__);
 
-       IRDA_ASSERT(dev != NULL, return 0;);
+       IRDA_ASSERT(dev != NULL, return NETDEV_TX_OK;);
 
        self = netdev_priv(dev);
-       IRDA_ASSERT(self != NULL, return 0;);
+       IRDA_ASSERT(self != NULL, return NETDEV_TX_OK;);
 
        netif_stop_queue(dev);
 
@@ -914,7 +914,7 @@ static int smsc_ircc_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev)
                        smsc_ircc_change_speed(self, speed);
                        spin_unlock_irqrestore(&self->lock, flags);
                        dev_kfree_skb(skb);
-                       return 0;
+                       return NETDEV_TX_OK;
                }
                self->new_speed = speed;
        }
@@ -935,7 +935,7 @@ static int smsc_ircc_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev)
 
        dev_kfree_skb(skb);
 
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 /*
@@ -1190,9 +1190,9 @@ static int smsc_ircc_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev)
        s32 speed;
        int mtt;
 
-       IRDA_ASSERT(dev != NULL, return 0;);
+       IRDA_ASSERT(dev != NULL, return NETDEV_TX_OK;);
        self = netdev_priv(dev);
-       IRDA_ASSERT(self != NULL, return 0;);
+       IRDA_ASSERT(self != NULL, return NETDEV_TX_OK;);
 
        netif_stop_queue(dev);
 
@@ -1210,7 +1210,7 @@ static int smsc_ircc_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev)
                        smsc_ircc_change_speed(self, speed);
                        spin_unlock_irqrestore(&self->lock, flags);
                        dev_kfree_skb(skb);
-                       return 0;
+                       return NETDEV_TX_OK;
                }
 
                self->new_speed = speed;
@@ -1242,7 +1242,7 @@ static int smsc_ircc_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev)
        spin_unlock_irqrestore(&self->lock, flags);
        dev_kfree_skb(skb);
 
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 /*
index 8e5e45c..c475b23 100644 (file)
@@ -578,7 +578,7 @@ static int stir_hard_xmit(struct sk_buff *skb, struct net_device *netdev)
                dev_kfree_skb(skb);
        }
 
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 /*
index 8647985..36a6074 100644 (file)
@@ -832,7 +832,7 @@ static int via_ircc_hard_xmit_sir(struct sk_buff *skb,
        __u32 speed;
 
        self = netdev_priv(dev);
-       IRDA_ASSERT(self != NULL, return 0;);
+       IRDA_ASSERT(self != NULL, return NETDEV_TX_OK;);
        iobase = self->io.fir_base;
 
        netif_stop_queue(dev);
@@ -844,7 +844,7 @@ static int via_ircc_hard_xmit_sir(struct sk_buff *skb,
                        via_ircc_change_speed(self, speed);
                        dev->trans_start = jiffies;
                        dev_kfree_skb(skb);
-                       return 0;
+                       return NETDEV_TX_OK;
                } else
                        self->new_speed = speed;
        }
@@ -892,7 +892,7 @@ static int via_ircc_hard_xmit_sir(struct sk_buff *skb,
        dev->trans_start = jiffies;
        spin_unlock_irqrestore(&self->lock, flags);
        dev_kfree_skb(skb);
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 static int via_ircc_hard_xmit_fir(struct sk_buff *skb,
@@ -907,7 +907,7 @@ static int via_ircc_hard_xmit_fir(struct sk_buff *skb,
        iobase = self->io.fir_base;
 
        if (self->st_fifo.len)
-               return 0;
+               return NETDEV_TX_OK;
        if (self->chip_id == 0x3076)
                iodelay(1500);
        else
@@ -919,7 +919,7 @@ static int via_ircc_hard_xmit_fir(struct sk_buff *skb,
                        via_ircc_change_speed(self, speed);
                        dev->trans_start = jiffies;
                        dev_kfree_skb(skb);
-                       return 0;
+                       return NETDEV_TX_OK;
                } else
                        self->new_speed = speed;
        }
@@ -940,7 +940,7 @@ static int via_ircc_hard_xmit_fir(struct sk_buff *skb,
        dev->trans_start = jiffies;
        dev_kfree_skb(skb);
        spin_unlock_irqrestore(&self->lock, flags);
-       return 0;
+       return NETDEV_TX_OK;
 
 }
 
index ac0e4b6..08e26f1 100644 (file)
@@ -915,7 +915,7 @@ static int vlsi_hard_start_xmit(struct sk_buff *skb, struct net_device *ndev)
                         */
                spin_unlock_irqrestore(&idev->lock, flags);
                dev_kfree_skb_any(skb);
-               return 0;
+               return NETDEV_TX_OK;
        }
 
        /* sanity checks - simply drop the packet */
@@ -1044,7 +1044,7 @@ static int vlsi_hard_start_xmit(struct sk_buff *skb, struct net_device *ndev)
        }
        spin_unlock_irqrestore(&idev->lock, flags);
 
-       return 0;
+       return NETDEV_TX_OK;
 
 drop_unlock:
        spin_unlock_irqrestore(&idev->lock, flags);
@@ -1058,7 +1058,7 @@ drop:
         * packet for later retry of transmission - which isn't exactly
         * what we want after we've just called dev_kfree_skb_any ;-)
         */
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 static void vlsi_tx_interrupt(struct net_device *ndev)
index d088383..49ef763 100644 (file)
@@ -516,7 +516,7 @@ static int w83977af_hard_xmit(struct sk_buff *skb, struct net_device *dev)
                        w83977af_change_speed(self, speed); 
                        dev->trans_start = jiffies;
                        dev_kfree_skb(skb);
-                       return 0;
+                       return NETDEV_TX_OK;
                } else
                        self->new_speed = speed;
        }
@@ -576,7 +576,7 @@ static int w83977af_hard_xmit(struct sk_buff *skb, struct net_device *dev)
        /* Restore set register */
        outb(set, iobase+SSR);
 
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 /*
index d12377b..9706e64 100644 (file)
@@ -468,7 +468,7 @@ static int net_send_packet(struct sk_buff *skb, struct net_device *dev)
        dev_kfree_skb (skb);
 #endif
 
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 #if TX_RING
index e44215c..e36e951 100644 (file)
@@ -1205,7 +1205,7 @@ static int veth_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
                if ( ! ((1 << rlp) & port->lpar_map) ) {
                        dev_kfree_skb(skb);
-                       return 0;
+                       return NETDEV_TX_OK;
                }
 
                lpmask = 1 << rlp;
@@ -1217,7 +1217,7 @@ static int veth_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
        dev_kfree_skb(skb);
 
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 /* You must hold the connection's lock when you call this function. */
index 9c897cf..eb917f1 100644 (file)
@@ -1459,7 +1459,7 @@ ixgb_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
 
        if (skb->len <= 0) {
                dev_kfree_skb(skb);
-               return 0;
+               return NETDEV_TX_OK;
        }
 
        if (unlikely(ixgb_maybe_stop_tx(netdev, &adapter->tx_ring,
index 1b12c7b..dc3cc43 100644 (file)
@@ -229,10 +229,6 @@ struct ixgbe_q_vector {
 #define IXGBE_TX_CTXTDESC_ADV(R, i)        \
        (&(((struct ixgbe_adv_tx_context_desc *)((R).desc))[i]))
 
-#define IXGBE_GET_DESC(R, i, type)     (&(((struct type *)((R).desc))[i]))
-#define IXGBE_TX_DESC(R, i)    IXGBE_GET_DESC(R, i, ixgbe_legacy_tx_desc)
-#define IXGBE_RX_DESC(R, i)    IXGBE_GET_DESC(R, i, ixgbe_legacy_rx_desc)
-
 #define IXGBE_MAX_JUMBO_FRAME_SIZE        16128
 #ifdef IXGBE_FCOE
 /* Use 3K as the baby jumbo frame size for FCoE */
index b992304..ed0bb3b 100644 (file)
@@ -269,6 +269,7 @@ static enum ixgbe_media_type ixgbe_get_media_type_82598(struct ixgbe_hw *hw)
                media_type = ixgbe_media_type_fiber;
                break;
        case IXGBE_DEV_ID_82598AT:
+       case IXGBE_DEV_ID_82598AT2:
                media_type = ixgbe_media_type_copper;
                break;
        default:
index 2a97800..1464b33 100644 (file)
@@ -1440,7 +1440,7 @@ static int ixgbe_setup_desc_rings(struct ixgbe_adapter *adapter)
                goto err_nomem;
        }
 
-       tx_ring->size = tx_ring->count * sizeof(struct ixgbe_legacy_tx_desc);
+       tx_ring->size = tx_ring->count * sizeof(union ixgbe_adv_tx_desc);
        tx_ring->size = ALIGN(tx_ring->size, 4096);
        if (!(tx_ring->desc = pci_alloc_consistent(pdev, tx_ring->size,
                                                   &tx_ring->dma))) {
@@ -1454,7 +1454,7 @@ static int ixgbe_setup_desc_rings(struct ixgbe_adapter *adapter)
        IXGBE_WRITE_REG(&adapter->hw, IXGBE_TDBAH(0),
                        ((u64) tx_ring->dma >> 32));
        IXGBE_WRITE_REG(&adapter->hw, IXGBE_TDLEN(0),
-                       tx_ring->count * sizeof(struct ixgbe_legacy_tx_desc));
+                       tx_ring->count * sizeof(union ixgbe_adv_tx_desc));
        IXGBE_WRITE_REG(&adapter->hw, IXGBE_TDH(0), 0);
        IXGBE_WRITE_REG(&adapter->hw, IXGBE_TDT(0), 0);
 
@@ -1472,7 +1472,7 @@ static int ixgbe_setup_desc_rings(struct ixgbe_adapter *adapter)
        IXGBE_WRITE_REG(&adapter->hw, IXGBE_TXDCTL(0), reg_data);
 
        for (i = 0; i < tx_ring->count; i++) {
-               struct ixgbe_legacy_tx_desc *desc = IXGBE_TX_DESC(*tx_ring, i);
+               union ixgbe_adv_tx_desc *desc = IXGBE_TX_DESC_ADV(*tx_ring, i);
                struct sk_buff *skb;
                unsigned int size = 1024;
 
@@ -1486,13 +1486,18 @@ static int ixgbe_setup_desc_rings(struct ixgbe_adapter *adapter)
                tx_ring->tx_buffer_info[i].length = skb->len;
                tx_ring->tx_buffer_info[i].dma =
                        pci_map_single(pdev, skb->data, skb->len,
-                                       PCI_DMA_TODEVICE);
-               desc->buffer_addr = cpu_to_le64(tx_ring->tx_buffer_info[i].dma);
-               desc->lower.data = cpu_to_le32(skb->len);
-               desc->lower.data |= cpu_to_le32(IXGBE_TXD_CMD_EOP |
-                                               IXGBE_TXD_CMD_IFCS |
-                                               IXGBE_TXD_CMD_RS);
-               desc->upper.data = 0;
+                                      PCI_DMA_TODEVICE);
+               desc->read.buffer_addr =
+                                   cpu_to_le64(tx_ring->tx_buffer_info[i].dma);
+               desc->read.cmd_type_len = cpu_to_le32(skb->len);
+               desc->read.cmd_type_len |= cpu_to_le32(IXGBE_TXD_CMD_EOP |
+                                                      IXGBE_TXD_CMD_IFCS |
+                                                      IXGBE_TXD_CMD_RS);
+               desc->read.olinfo_status = 0;
+               if (adapter->hw.mac.type == ixgbe_mac_82599EB)
+                       desc->read.olinfo_status |=
+                                       (skb->len << IXGBE_ADVTXD_PAYLEN_SHIFT);
+
        }
 
        /* Setup Rx Descriptor ring and Rx buffers */
@@ -1508,7 +1513,7 @@ static int ixgbe_setup_desc_rings(struct ixgbe_adapter *adapter)
                goto err_nomem;
        }
 
-       rx_ring->size = rx_ring->count * sizeof(struct ixgbe_legacy_rx_desc);
+       rx_ring->size = rx_ring->count * sizeof(union ixgbe_adv_rx_desc);
        rx_ring->size = ALIGN(rx_ring->size, 4096);
        if (!(rx_ring->desc = pci_alloc_consistent(pdev, rx_ring->size,
                                                   &rx_ring->dma))) {
@@ -1566,8 +1571,8 @@ static int ixgbe_setup_desc_rings(struct ixgbe_adapter *adapter)
        IXGBE_WRITE_REG(&adapter->hw, IXGBE_RXCTRL, rctl);
 
        for (i = 0; i < rx_ring->count; i++) {
-               struct ixgbe_legacy_rx_desc *rx_desc =
-                                       IXGBE_RX_DESC(*rx_ring, i);
+               union ixgbe_adv_rx_desc *rx_desc =
+                                                IXGBE_RX_DESC_ADV(*rx_ring, i);
                struct sk_buff *skb;
 
                skb = alloc_skb(IXGBE_RXBUFFER_2048 + NET_IP_ALIGN, GFP_KERNEL);
@@ -1580,7 +1585,7 @@ static int ixgbe_setup_desc_rings(struct ixgbe_adapter *adapter)
                rx_ring->rx_buffer_info[i].dma =
                        pci_map_single(pdev, skb->data, IXGBE_RXBUFFER_2048,
                                       PCI_DMA_FROMDEVICE);
-               rx_desc->buffer_addr =
+               rx_desc->read.pkt_addr =
                                cpu_to_le64(rx_ring->rx_buffer_info[i].dma);
                memset(skb->data, 0x00, skb->len);
        }
index 6887759..50709da 100644 (file)
@@ -49,7 +49,7 @@ char ixgbe_driver_name[] = "ixgbe";
 static const char ixgbe_driver_string[] =
                               "Intel(R) 10 Gigabit PCI Express Network Driver";
 
-#define DRV_VERSION "2.0.34-k2"
+#define DRV_VERSION "2.0.37-k2"
 const char ixgbe_driver_version[] = DRV_VERSION;
 static char ixgbe_copyright[] = "Copyright (c) 1999-2009 Intel Corporation.";
 
@@ -75,6 +75,8 @@ static struct pci_device_id ixgbe_pci_tbl[] = {
         board_82598 },
        {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598AT),
         board_82598 },
+       {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598AT2),
+        board_82598 },
        {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598EB_CX4),
         board_82598 },
        {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598_CX4_DUAL_PORT),
@@ -4645,13 +4647,13 @@ static void ixgbe_watchdog_task(struct work_struct *work)
                        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);
+                               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);
+                               flow_rx = !!(frctl & IXGBE_FCTRL_RFCE);
+                               flow_tx = !!(rmcs & IXGBE_RMCS_TFCE_802_3X);
                        }
 
                        printk(KERN_INFO "ixgbe: %s NIC Link is Up %s, "
index fa87309..17ee389 100644 (file)
@@ -42,6 +42,7 @@
 #define IXGBE_DEV_ID_82598AF_SINGLE_PORT 0x10C7
 #define IXGBE_DEV_ID_82598EB_SFP_LOM     0x10DB
 #define IXGBE_DEV_ID_82598AT             0x10C8
+#define IXGBE_DEV_ID_82598AT2            0x150B
 #define IXGBE_DEV_ID_82598EB_CX4         0x10DD
 #define IXGBE_DEV_ID_82598_CX4_DUAL_PORT 0x10EC
 #define IXGBE_DEV_ID_82598_DA_DUAL_PORT  0x10F1
@@ -1893,27 +1894,6 @@ enum ixgbe_fdir_pballoc_type {
 #define IXGBE_FDIR_INIT_DONE_POLL               10
 #define IXGBE_FDIRCMD_CMD_POLL                  10
 
-/* Transmit Descriptor - Legacy */
-struct ixgbe_legacy_tx_desc {
-       u64 buffer_addr;       /* Address of the descriptor's data buffer */
-       union {
-               __le32 data;
-               struct {
-                       __le16 length;    /* Data buffer length */
-                       u8 cso;           /* Checksum offset */
-                       u8 cmd;           /* Descriptor control */
-               } flags;
-       } lower;
-       union {
-               __le32 data;
-               struct {
-                       u8 status;        /* Descriptor status */
-                       u8 css;           /* Checksum start */
-                       __le16 vlan;
-               } fields;
-       } upper;
-};
-
 /* Transmit Descriptor - Advanced */
 union ixgbe_adv_tx_desc {
        struct {
@@ -1928,16 +1908,6 @@ union ixgbe_adv_tx_desc {
        } wb;
 };
 
-/* Receive Descriptor - Legacy */
-struct ixgbe_legacy_rx_desc {
-       __le64 buffer_addr; /* Address of the descriptor's data buffer */
-       __le16 length;      /* Length of data DMAed into data buffer */
-       __le16 csum;        /* Packet checksum */
-       u8 status;          /* Descriptor status */
-       u8 errors;          /* Descriptor Errors */
-       __le16 vlan;
-};
-
 /* Receive Descriptor - Advanced */
 union ixgbe_adv_rx_desc {
        struct {
index 2a0174b..588b44d 100644 (file)
@@ -45,7 +45,7 @@ static int ixpdev_xmit(struct sk_buff *skb, struct net_device *dev)
        if (unlikely(skb->len > PAGE_SIZE)) {
                /* @@@ Count drops.  */
                dev_kfree_skb(skb);
-               return 0;
+               return NETDEV_TX_OK;
        }
 
        entry = tx_pointer;
@@ -69,7 +69,7 @@ static int ixpdev_xmit(struct sk_buff *skb, struct net_device *dev)
                netif_stop_queue(dev);
        local_irq_enable();
 
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 
index 2f28609..ec337b5 100644 (file)
@@ -108,7 +108,7 @@ static const struct net_device_ops sonic_netdev_ops = {
        .ndo_set_mac_address    = eth_mac_addr,
 };
 
-static int __init sonic_probe1(struct net_device *dev)
+static int __devinit sonic_probe1(struct net_device *dev)
 {
        static unsigned version_printed;
        unsigned int silicon_revision;
@@ -211,7 +211,7 @@ out:
  * Probe for a SONIC ethernet controller on a Mips Jazz board.
  * Actually probing is superfluous but we're paranoid.
  */
-static int __init jazz_sonic_probe(struct platform_device *pdev)
+static int __devinit jazz_sonic_probe(struct platform_device *pdev)
 {
        struct net_device *dev;
        struct sonic_local *lp;
index 1e3c63d..e7068c7 100644 (file)
@@ -322,20 +322,6 @@ jme_stop_irq(struct jme_adapter *jme)
        jwrite32f(jme, JME_IENC, INTR_ENABLE);
 }
 
-static inline void
-jme_enable_shadow(struct jme_adapter *jme)
-{
-       jwrite32(jme,
-                JME_SHBA_LO,
-                ((u32)jme->shadow_dma & ~((u32)0x1F)) | SHBA_POSTEN);
-}
-
-static inline void
-jme_disable_shadow(struct jme_adapter *jme)
-{
-       jwrite32(jme, JME_SHBA_LO, 0x0);
-}
-
 static u32
 jme_linkstat_from_phy(struct jme_adapter *jme)
 {
@@ -522,12 +508,8 @@ jme_setup_tx_resources(struct jme_adapter *jme)
                                   &(txring->dmaalloc),
                                   GFP_ATOMIC);
 
-       if (!txring->alloc) {
-               txring->desc = NULL;
-               txring->dmaalloc = 0;
-               txring->dma = 0;
-               return -ENOMEM;
-       }
+       if (!txring->alloc)
+               goto err_set_null;
 
        /*
         * 16 Bytes align
@@ -539,6 +521,11 @@ jme_setup_tx_resources(struct jme_adapter *jme)
        atomic_set(&txring->next_to_clean, 0);
        atomic_set(&txring->nr_free, jme->tx_ring_size);
 
+       txring->bufinf          = kmalloc(sizeof(struct jme_buffer_info) *
+                                       jme->tx_ring_size, GFP_ATOMIC);
+       if (unlikely(!(txring->bufinf)))
+               goto err_free_txring;
+
        /*
         * Initialize Transmit Descriptors
         */
@@ -547,6 +534,20 @@ jme_setup_tx_resources(struct jme_adapter *jme)
                sizeof(struct jme_buffer_info) * jme->tx_ring_size);
 
        return 0;
+
+err_free_txring:
+       dma_free_coherent(&(jme->pdev->dev),
+                         TX_RING_ALLOC_SIZE(jme->tx_ring_size),
+                         txring->alloc,
+                         txring->dmaalloc);
+
+err_set_null:
+       txring->desc = NULL;
+       txring->dmaalloc = 0;
+       txring->dma = 0;
+       txring->bufinf = NULL;
+
+       return -ENOMEM;
 }
 
 static void
@@ -554,19 +555,22 @@ jme_free_tx_resources(struct jme_adapter *jme)
 {
        int i;
        struct jme_ring *txring = &(jme->txring[0]);
-       struct jme_buffer_info *txbi = txring->bufinf;
+       struct jme_buffer_info *txbi;
 
        if (txring->alloc) {
-               for (i = 0 ; i < jme->tx_ring_size ; ++i) {
-                       txbi = txring->bufinf + i;
-                       if (txbi->skb) {
-                               dev_kfree_skb(txbi->skb);
-                               txbi->skb = NULL;
+               if (txring->bufinf) {
+                       for (i = 0 ; i < jme->tx_ring_size ; ++i) {
+                               txbi = txring->bufinf + i;
+                               if (txbi->skb) {
+                                       dev_kfree_skb(txbi->skb);
+                                       txbi->skb = NULL;
+                               }
+                               txbi->mapping           = 0;
+                               txbi->len               = 0;
+                               txbi->nr_desc           = 0;
+                               txbi->start_xmit        = 0;
                        }
-                       txbi->mapping           = 0;
-                       txbi->len               = 0;
-                       txbi->nr_desc           = 0;
-                       txbi->start_xmit        = 0;
+                       kfree(txring->bufinf);
                }
 
                dma_free_coherent(&(jme->pdev->dev),
@@ -578,11 +582,11 @@ jme_free_tx_resources(struct jme_adapter *jme)
                txring->desc            = NULL;
                txring->dmaalloc        = 0;
                txring->dma             = 0;
+               txring->bufinf          = NULL;
        }
        txring->next_to_use     = 0;
        atomic_set(&txring->next_to_clean, 0);
        atomic_set(&txring->nr_free, 0);
-
 }
 
 static inline void
@@ -653,7 +657,7 @@ jme_disable_tx_engine(struct jme_adapter *jme)
 static void
 jme_set_clean_rxdesc(struct jme_adapter *jme, int i)
 {
-       struct jme_ring *rxring = jme->rxring;
+       struct jme_ring *rxring = &(jme->rxring[0]);
        register struct rxdesc *rxdesc = rxring->desc;
        struct jme_buffer_info *rxbi = rxring->bufinf;
        rxdesc += i;
@@ -720,8 +724,11 @@ jme_free_rx_resources(struct jme_adapter *jme)
        struct jme_ring *rxring = &(jme->rxring[0]);
 
        if (rxring->alloc) {
-               for (i = 0 ; i < jme->rx_ring_size ; ++i)
-                       jme_free_rx_buf(jme, i);
+               if (rxring->bufinf) {
+                       for (i = 0 ; i < jme->rx_ring_size ; ++i)
+                               jme_free_rx_buf(jme, i);
+                       kfree(rxring->bufinf);
+               }
 
                dma_free_coherent(&(jme->pdev->dev),
                                  RX_RING_ALLOC_SIZE(jme->rx_ring_size),
@@ -731,6 +738,7 @@ jme_free_rx_resources(struct jme_adapter *jme)
                rxring->desc     = NULL;
                rxring->dmaalloc = 0;
                rxring->dma      = 0;
+               rxring->bufinf   = NULL;
        }
        rxring->next_to_use   = 0;
        atomic_set(&rxring->next_to_clean, 0);
@@ -746,12 +754,8 @@ jme_setup_rx_resources(struct jme_adapter *jme)
                                   RX_RING_ALLOC_SIZE(jme->rx_ring_size),
                                   &(rxring->dmaalloc),
                                   GFP_ATOMIC);
-       if (!rxring->alloc) {
-               rxring->desc = NULL;
-               rxring->dmaalloc = 0;
-               rxring->dma = 0;
-               return -ENOMEM;
-       }
+       if (!rxring->alloc)
+               goto err_set_null;
 
        /*
         * 16 Bytes align
@@ -762,9 +766,16 @@ jme_setup_rx_resources(struct jme_adapter *jme)
        rxring->next_to_use     = 0;
        atomic_set(&rxring->next_to_clean, 0);
 
+       rxring->bufinf          = kmalloc(sizeof(struct jme_buffer_info) *
+                                       jme->rx_ring_size, GFP_ATOMIC);
+       if (unlikely(!(rxring->bufinf)))
+               goto err_free_rxring;
+
        /*
         * Initiallize Receive Descriptors
         */
+       memset(rxring->bufinf, 0,
+               sizeof(struct jme_buffer_info) * jme->rx_ring_size);
        for (i = 0 ; i < jme->rx_ring_size ; ++i) {
                if (unlikely(jme_make_new_rx_buf(jme, i))) {
                        jme_free_rx_resources(jme);
@@ -775,6 +786,19 @@ jme_setup_rx_resources(struct jme_adapter *jme)
        }
 
        return 0;
+
+err_free_rxring:
+       dma_free_coherent(&(jme->pdev->dev),
+                         RX_RING_ALLOC_SIZE(jme->rx_ring_size),
+                         rxring->alloc,
+                         rxring->dmaalloc);
+err_set_null:
+       rxring->desc = NULL;
+       rxring->dmaalloc = 0;
+       rxring->dma = 0;
+       rxring->bufinf = NULL;
+
+       return -ENOMEM;
 }
 
 static inline void
@@ -790,9 +814,9 @@ jme_enable_rx_engine(struct jme_adapter *jme)
        /*
         * Setup RX DMA Bass Address
         */
-       jwrite32(jme, JME_RXDBA_LO, (__u64)jme->rxring[0].dma & 0xFFFFFFFFUL);
+       jwrite32(jme, JME_RXDBA_LO, (__u64)(jme->rxring[0].dma) & 0xFFFFFFFFUL);
        jwrite32(jme, JME_RXDBA_HI, (__u64)(jme->rxring[0].dma) >> 32);
-       jwrite32(jme, JME_RXNDA, (__u64)jme->rxring[0].dma & 0xFFFFFFFFUL);
+       jwrite32(jme, JME_RXNDA, (__u64)(jme->rxring[0].dma) & 0xFFFFFFFFUL);
 
        /*
         * Setup RX Descriptor Count
@@ -856,27 +880,27 @@ jme_rxsum_ok(struct jme_adapter *jme, u16 flags)
        if (!(flags & (RXWBFLAG_TCPON | RXWBFLAG_UDPON | RXWBFLAG_IPV4)))
                return false;
 
-       if (unlikely(!(flags & RXWBFLAG_MF) &&
-       (flags & RXWBFLAG_TCPON) && !(flags & RXWBFLAG_TCPCS))) {
-               msg_rx_err(jme, "TCP Checksum error.\n");
-               goto out_sumerr;
+       if (unlikely((flags & (RXWBFLAG_MF | RXWBFLAG_TCPON | RXWBFLAG_TCPCS))
+                       == RXWBFLAG_TCPON)) {
+               if (flags & RXWBFLAG_IPV4)
+                       msg_rx_err(jme, "TCP Checksum error\n");
+               return false;
        }
 
-       if (unlikely(!(flags & RXWBFLAG_MF) &&
-       (flags & RXWBFLAG_UDPON) && !(flags & RXWBFLAG_UDPCS))) {
-               msg_rx_err(jme, "UDP Checksum error.\n");
-               goto out_sumerr;
+       if (unlikely((flags & (RXWBFLAG_MF | RXWBFLAG_UDPON | RXWBFLAG_UDPCS))
+                       == RXWBFLAG_UDPON)) {
+               if (flags & RXWBFLAG_IPV4)
+                       msg_rx_err(jme, "UDP Checksum error.\n");
+               return false;
        }
 
-       if (unlikely((flags & RXWBFLAG_IPV4) && !(flags & RXWBFLAG_IPCS))) {
+       if (unlikely((flags & (RXWBFLAG_IPV4 | RXWBFLAG_IPCS))
+                       == RXWBFLAG_IPV4)) {
                msg_rx_err(jme, "IPv4 Checksum error.\n");
-               goto out_sumerr;
+               return false;
        }
 
        return true;
-
-out_sumerr:
-       return false;
 }
 
 static void
@@ -1296,7 +1320,7 @@ jme_rx_empty_tasklet(unsigned long arg)
 static void
 jme_wake_queue_if_stopped(struct jme_adapter *jme)
 {
-       struct jme_ring *txring = jme->txring;
+       struct jme_ring *txring = &(jme->txring[0]);
 
        smp_wmb();
        if (unlikely(netif_queue_stopped(jme->dev) &&
@@ -1483,12 +1507,7 @@ jme_msi(int irq, void *dev_id)
        struct jme_adapter *jme = netdev_priv(netdev);
        u32 intrstat;
 
-       pci_dma_sync_single_for_cpu(jme->pdev,
-                                   jme->shadow_dma,
-                                   sizeof(u32) * SHADOW_REG_NR,
-                                   PCI_DMA_FROMDEVICE);
-       intrstat = jme->shadow_regs[SHADOW_IEVE];
-       jme->shadow_regs[SHADOW_IEVE] = 0;
+       intrstat = jread32(jme, JME_IEVE);
 
        jme_intr_msi(jme, intrstat);
 
@@ -1566,6 +1585,7 @@ jme_open(struct net_device *netdev)
        jme_clear_pm(jme);
        JME_NAPI_ENABLE(jme);
 
+       tasklet_enable(&jme->linkch_task);
        tasklet_enable(&jme->txclean_task);
        tasklet_hi_enable(&jme->rxclean_task);
        tasklet_hi_enable(&jme->rxempty_task);
@@ -1574,7 +1594,6 @@ jme_open(struct net_device *netdev)
        if (rc)
                goto err_out;
 
-       jme_enable_shadow(jme);
        jme_start_irq(jme);
 
        if (test_bit(JME_FLAG_SSET, &jme->flags))
@@ -1642,15 +1661,14 @@ jme_close(struct net_device *netdev)
        netif_carrier_off(netdev);
 
        jme_stop_irq(jme);
-       jme_disable_shadow(jme);
        jme_free_irq(jme);
 
        JME_NAPI_DISABLE(jme);
 
-       tasklet_kill(&jme->linkch_task);
-       tasklet_kill(&jme->txclean_task);
-       tasklet_kill(&jme->rxclean_task);
-       tasklet_kill(&jme->rxempty_task);
+       tasklet_disable(&jme->linkch_task);
+       tasklet_disable(&jme->txclean_task);
+       tasklet_disable(&jme->rxclean_task);
+       tasklet_disable(&jme->rxempty_task);
 
        jme_reset_ghc_speed(jme);
        jme_disable_rx_engine(jme);
@@ -1668,7 +1686,7 @@ static int
 jme_alloc_txdesc(struct jme_adapter *jme,
                        struct sk_buff *skb)
 {
-       struct jme_ring *txring = jme->txring;
+       struct jme_ring *txring = &(jme->txring[0]);
        int idx, nr_alloc, mask = jme->tx_ring_mask;
 
        idx = txring->next_to_use;
@@ -1722,7 +1740,7 @@ jme_fill_tx_map(struct pci_dev *pdev,
 static void
 jme_map_tx_skb(struct jme_adapter *jme, struct sk_buff *skb, int idx)
 {
-       struct jme_ring *txring = jme->txring;
+       struct jme_ring *txring = &(jme->txring[0]);
        struct txdesc *txdesc = txring->desc, *ctxdesc;
        struct jme_buffer_info *txbi = txring->bufinf, *ctxbi;
        u8 hidma = jme->dev->features & NETIF_F_HIGHDMA;
@@ -1835,7 +1853,7 @@ jme_tx_vlan(struct sk_buff *skb, __le16 *vlan, u8 *flags)
 static int
 jme_fill_tx_desc(struct jme_adapter *jme, struct sk_buff *skb, int idx)
 {
-       struct jme_ring *txring = jme->txring;
+       struct jme_ring *txring = &(jme->txring[0]);
        struct txdesc *txdesc;
        struct jme_buffer_info *txbi;
        u8 flags;
@@ -1883,7 +1901,7 @@ jme_fill_tx_desc(struct jme_adapter *jme, struct sk_buff *skb, int idx)
 static void
 jme_stop_queue_if_full(struct jme_adapter *jme)
 {
-       struct jme_ring *txring = jme->txring;
+       struct jme_ring *txring = &(jme->txring[0]);
        struct jme_buffer_info *txbi = txring->bufinf;
        int idx = atomic_read(&txring->next_to_clean);
 
@@ -2725,14 +2743,6 @@ jme_init_one(struct pci_dev *pdev,
                rc = -ENOMEM;
                goto err_out_free_netdev;
        }
-       jme->shadow_regs = pci_alloc_consistent(pdev,
-                                               sizeof(u32) * SHADOW_REG_NR,
-                                               &(jme->shadow_dma));
-       if (!(jme->shadow_regs)) {
-               jeprintk(pdev, "Allocating shadow register mapping error.\n");
-               rc = -ENOMEM;
-               goto err_out_unmap;
-       }
 
        if (no_pseudohp) {
                apmc = jread32(jme, JME_APMC) & ~JME_APMC_PSEUDO_HP_EN;
@@ -2768,6 +2778,7 @@ jme_init_one(struct pci_dev *pdev,
        tasklet_init(&jme->rxempty_task,
                     &jme_rx_empty_tasklet,
                     (unsigned long) jme);
+       tasklet_disable_nosync(&jme->linkch_task);
        tasklet_disable_nosync(&jme->txclean_task);
        tasklet_disable_nosync(&jme->rxclean_task);
        tasklet_disable_nosync(&jme->rxempty_task);
@@ -2817,7 +2828,7 @@ jme_init_one(struct pci_dev *pdev,
                if (!jme->mii_if.phy_id) {
                        rc = -EIO;
                        jeprintk(pdev, "Can not find phy_id.\n");
-                        goto err_out_free_shadow;
+                        goto err_out_unmap;
                }
 
                jme->reg_ghc |= GHC_LINK_POLL;
@@ -2846,7 +2857,7 @@ jme_init_one(struct pci_dev *pdev,
        if (rc) {
                jeprintk(pdev,
                        "Reload eeprom for reading MAC Address error.\n");
-               goto err_out_free_shadow;
+               goto err_out_unmap;
        }
        jme_load_macaddr(netdev);
 
@@ -2862,7 +2873,7 @@ jme_init_one(struct pci_dev *pdev,
        rc = register_netdev(netdev);
        if (rc) {
                jeprintk(pdev, "Cannot register net device.\n");
-               goto err_out_free_shadow;
+               goto err_out_unmap;
        }
 
        msg_probe(jme, "%s%s ver:%x rev:%x macaddr:%pM\n",
@@ -2876,11 +2887,6 @@ jme_init_one(struct pci_dev *pdev,
 
        return 0;
 
-err_out_free_shadow:
-       pci_free_consistent(pdev,
-                           sizeof(u32) * SHADOW_REG_NR,
-                           jme->shadow_regs,
-                           jme->shadow_dma);
 err_out_unmap:
        iounmap(jme->regs);
 err_out_free_netdev:
@@ -2901,10 +2907,6 @@ jme_remove_one(struct pci_dev *pdev)
        struct jme_adapter *jme = netdev_priv(netdev);
 
        unregister_netdev(netdev);
-       pci_free_consistent(pdev,
-                           sizeof(u32) * SHADOW_REG_NR,
-                           jme->shadow_regs,
-                           jme->shadow_dma);
        iounmap(jme->regs);
        pci_set_drvdata(pdev, NULL);
        free_netdev(netdev);
@@ -2930,8 +2932,6 @@ jme_suspend(struct pci_dev *pdev, pm_message_t state)
        tasklet_disable(&jme->rxclean_task);
        tasklet_disable(&jme->rxempty_task);
 
-       jme_disable_shadow(jme);
-
        if (netif_carrier_ok(netdev)) {
                if (test_bit(JME_FLAG_POLL, &jme->flags))
                        jme_polling_mode(jme);
@@ -2983,7 +2983,6 @@ jme_resume(struct pci_dev *pdev)
        else
                jme_reset_phy_processor(jme);
 
-       jme_enable_shadow(jme);
        jme_start_irq(jme);
        netif_device_attach(netdev);
 
index 0996a06..251abed 100644 (file)
@@ -25,7 +25,7 @@
 #define __JME_H_INCLUDED__
 
 #define DRV_NAME       "jme"
-#define DRV_VERSION    "1.0.4"
+#define DRV_VERSION    "1.0.5"
 #define PFX            DRV_NAME ": "
 
 #define PCI_DEVICE_ID_JMICRON_JMC250   0x0250
@@ -247,7 +247,7 @@ enum jme_txdesc_flags_bits {
 };
 
 #define TXDESC_MSS_SHIFT       2
-enum jme_rxdescwb_flags_bits {
+enum jme_txwbdesc_flags_bits {
        TXWBFLAG_OWN    = 0x80,
        TXWBFLAG_INT    = 0x40,
        TXWBFLAG_TMOUT  = 0x20,
@@ -372,7 +372,6 @@ struct jme_buffer_info {
 /*
  * The structure holding buffer information and ring descriptors all together.
  */
-#define MAX_RING_DESC_NR       1024
 struct jme_ring {
        void *alloc;            /* pointer to allocated memory */
        void *desc;             /* pointer to ring memory  */
@@ -380,7 +379,7 @@ struct jme_ring {
        dma_addr_t dma;         /* phys address for ring dma */
 
        /* Buffer information corresponding to each descriptor */
-       struct jme_buffer_info bufinf[MAX_RING_DESC_NR];
+       struct jme_buffer_info *bufinf;
 
        int next_to_use;
        atomic_t next_to_clean;
@@ -411,13 +410,10 @@ struct jme_ring {
 /*
  * Jmac Adapter Private data
  */
-#define SHADOW_REG_NR 8
 struct jme_adapter {
        struct pci_dev          *pdev;
        struct net_device       *dev;
        void __iomem            *regs;
-       dma_addr_t              shadow_dma;
-       u32                     *shadow_regs;
        struct mii_if_info      mii_if;
        struct jme_ring         rxring[RX_RING_NR];
        struct jme_ring         txring[TX_RING_NR];
@@ -464,10 +460,6 @@ struct jme_adapter {
        DECLARE_NET_DEVICE_STATS
 };
 
-enum shadow_reg_val {
-       SHADOW_IEVE = 0,
-};
-
 enum jme_flags_bits {
        JME_FLAG_MSI            = 1,
        JME_FLAG_SSET           = 2,
@@ -1104,13 +1096,6 @@ enum jme_chipmode_shifts {
 };
 
 /*
- * Shadow base address register bits
- */
-enum jme_shadow_base_address_bits {
-       SHBA_POSTEN     = 0x1,
-};
-
-/*
  * Aggressive Power Mode Control
  */
 enum jme_apmc_bits {
index 633808d..30fd4f5 100644 (file)
@@ -1016,7 +1016,7 @@ static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
 out:
        spin_unlock_irqrestore(&lp->devlock, flags);
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 /* The LANCE interrupt handler. */
index 070fa45..51e11c3 100644 (file)
@@ -983,7 +983,7 @@ static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
        if (length < ETH_ZLEN) {
                if (skb_padto(skb, ETH_ZLEN))
-                       return 0;
+                       return NETDEV_TX_OK;
                length = ETH_ZLEN;
        }
 
@@ -1028,7 +1028,7 @@ static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
        netif_start_queue(dev);
 
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 static void print_eth(unsigned char *add, char *str)
index f28c233..d6be360 100644 (file)
@@ -414,7 +414,7 @@ static int __ei_start_xmit(struct sk_buff *skb, struct net_device *dev)
        dev_kfree_skb (skb);
        dev->stats.tx_bytes += send_length;
 
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 /**
index 96e7248..da8d0a0 100644 (file)
@@ -591,7 +591,7 @@ static int temac_start_xmit(struct sk_buff *skb, struct net_device *ndev)
        /* Kick off the transfer */
        temac_dma_out32(lp, TX_TAILDESC_PTR, tail_p); /* DMA start */
 
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 
index da472c6..51bbce7 100644 (file)
@@ -89,7 +89,7 @@ static int loopback_xmit(struct sk_buff *skb, struct net_device *dev)
        } else
                lb_stats->drops++;
 
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 static struct net_device_stats *loopback_get_stats(struct net_device *dev)
index d44bddb..c292bad 100644 (file)
@@ -871,7 +871,7 @@ static int i596_start_xmit (struct sk_buff *skb, struct net_device *dev) {
 
        if (length < ETH_ZLEN) {
                if (skb_padto(skb, ETH_ZLEN))
-                       return 0;
+                       return NETDEV_TX_OK;
                length = ETH_ZLEN;
        }
 
@@ -906,7 +906,7 @@ static int i596_start_xmit (struct sk_buff *skb, struct net_device *dev) {
                dev->stats.tx_packets++;
        }
 
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 static void
index dab4533..149e0ed 100644 (file)
@@ -411,7 +411,7 @@ net_send_packet(struct sk_buff *skb, struct net_device *dev)
        dev->trans_start = jiffies;
        dev_kfree_skb (skb);
 
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 /* The typical workload of the driver:
index 5b5c253..d22952c 100644 (file)
@@ -678,7 +678,7 @@ static int macb_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
        dev->trans_start = jiffies;
 
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 static void macb_free_consistent(struct macb *bp)
index 1427755..7d7577b 100644 (file)
@@ -581,7 +581,7 @@ static int mace_xmit_start(struct sk_buff *skb, struct net_device *dev)
        netif_stop_queue(dev);
     spin_unlock_irqrestore(&mp->lock, flags);
 
-    return 0;
+    return NETDEV_TX_OK;
 }
 
 static void mace_set_multicast(struct net_device *dev)
index 5d04d94..92ceb68 100644 (file)
@@ -715,7 +715,7 @@ static int meth_tx(struct sk_buff *skb, struct net_device *dev)
 
        spin_unlock_irqrestore(&priv->meth_lock, flags);
 
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 /*
@@ -784,7 +784,7 @@ static const struct net_device_ops meth_netdev_ops = {
 /*
  * The init function.
  */
-static int __init meth_probe(struct platform_device *pdev)
+static int __devinit meth_probe(struct platform_device *pdev)
 {
        struct net_device *dev;
        struct meth_private *priv;
index b3b9a14..8ea98bd 100644 (file)
@@ -141,7 +141,7 @@ static int mipsnet_xmit(struct sk_buff *skb, struct net_device *dev)
        netif_stop_queue(dev);
        mipsnet_put_todevice(dev, skb);
 
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 static inline ssize_t mipsnet_get_fromdev(struct net_device *dev, size_t len)
index 08c43f2..d5c18c6 100644 (file)
@@ -764,7 +764,7 @@ int mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev)
        /* Poll CQ here */
        mlx4_en_xmit_poll(priv, tx_ind);
 
-       return 0;
+       return NETDEV_TX_OK;
 
 tx_drop:
        dev_kfree_skb_any(skb);
index 1f6e36e..1a34f7e 100644 (file)
@@ -2748,7 +2748,7 @@ again:
                                /* The packet is gone, so we must
                                 * return 0 */
                                ss->stats.tx_dropped += 1;
-                               return 0;
+                               return NETDEV_TX_OK;
                        }
                        /* adjust the len to account for the zero pad
                         * so that the nic can know how long it is */
@@ -2892,7 +2892,7 @@ again:
                tx->stop_queue++;
                netif_tx_stop_queue(netdev_queue);
        }
-       return 0;
+       return NETDEV_TX_OK;
 
 abort_linearize:
        /* Free any DMA resources we've alloced and clear out the skb
@@ -2936,7 +2936,7 @@ abort_linearize:
 drop:
        dev_kfree_skb_any(skb);
        ss->stats.tx_dropped += 1;
-       return 0;
+       return NETDEV_TX_OK;
 
 }
 
@@ -2968,13 +2968,13 @@ static int myri10ge_sw_tso(struct sk_buff *skb, struct net_device *dev)
                }
        }
        dev_kfree_skb_any(skb);
-       return 0;
+       return NETDEV_TX_OK;
 
 drop:
        ss = &mgp->ss[skb_get_queue_mapping(skb)];
        dev_kfree_skb_any(skb);
        ss->stats.tx_dropped += 1;
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 static struct net_device_stats *myri10ge_get_stats(struct net_device *dev)
index 5f0758b..29ebebc 100644 (file)
@@ -692,7 +692,7 @@ static int myri_start_xmit(struct sk_buff *skb, struct net_device *dev)
        DTX(("tbusy=0, returning 0\n"));
        netif_start_queue(dev);
        spin_unlock_irqrestore(&mp->irq_lock, flags);
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 /* Create the MyriNet MAC header for an arbitrary protocol layer
index c9bfe4e..481aa2d 100644 (file)
@@ -2125,7 +2125,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev)
                printk(KERN_DEBUG "%s: Transmit frame #%d queued in slot %d.\n",
                        dev->name, np->cur_tx, entry);
        }
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 static void netdev_tx_done(struct net_device *dev)
index 946366d..9f42354 100644 (file)
@@ -134,7 +134,7 @@ netx_eth_hard_start_xmit(struct sk_buff *skb, struct net_device *ndev)
        spin_unlock_irq(&priv->lock);
        dev_kfree_skb(skb);
 
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 static void netx_eth_receive(struct net_device *ndev)
index 2a8da47..462d20f 100644 (file)
@@ -463,7 +463,7 @@ static int ni5010_send_packet(struct sk_buff *skb, struct net_device *dev)
        hardware_send_packet(dev, (unsigned char *)skb->data, skb->len, length-skb->len);
        dev->trans_start = jiffies;
        dev_kfree_skb (skb);
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 /*
index 77d44a0..a0ac5d4 100644 (file)
@@ -1183,7 +1183,7 @@ static int ni52_send_packet(struct sk_buff *skb, struct net_device *dev)
 
        if (skb->len > XMIT_BUFF_SIZE) {
                printk(KERN_ERR "%s: Sorry, max. framelength is %d bytes. The length of your frame is %d bytes.\n", dev->name, XMIT_BUFF_SIZE, skb->len);
-               return 0;
+               return NETDEV_TX_OK;
        }
 
        netif_stop_queue(dev);
@@ -1267,7 +1267,7 @@ static int ni52_send_packet(struct sk_buff *skb, struct net_device *dev)
        }
        dev_kfree_skb(skb);
 #endif
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 /*******************************************
index 1f10ed6..81a0617 100644 (file)
@@ -1216,7 +1216,7 @@ static int ni65_send_packet(struct sk_buff *skb, struct net_device *dev)
                spin_unlock_irqrestore(&p->ring_lock, flags);
        }
 
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 static void set_multicast_list(struct net_device *dev)
index 8c1f698..e4a93b8 100644 (file)
@@ -1356,7 +1356,7 @@ static int netdrv_start_xmit (struct sk_buff *skb, struct net_device *dev)
        DPRINTK ("%s: Queued Tx packet at %p size %u to slot %d.\n",
                 dev->name, skb->data, skb->len, entry);
 
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 
index f35c609..a23aa87 100644 (file)
@@ -806,7 +806,7 @@ static int el3_start_xmit(struct sk_buff *skb, struct net_device *dev)
        pop_tx_status(dev);
        spin_unlock_irqrestore(&lp->window_lock, flags);
        dev_kfree_skb(skb);
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 /* The EL3 interrupt handler. */
index 690b9c7..d2156ab 100644 (file)
@@ -635,7 +635,7 @@ static int el3_start_xmit(struct sk_buff *skb, struct net_device *dev)
     spin_unlock_irqrestore(&priv->lock, flags);    
     dev_kfree_skb(skb);
     
-    return 0;
+    return NETDEV_TX_OK;
 }
 
 /* The EL3 interrupt handler. */
index 0e38d80..b5cfac7 100644 (file)
@@ -1179,7 +1179,7 @@ static int axnet_start_xmit(struct sk_buff *skb, struct net_device *dev)
        dev_kfree_skb (skb);
        dev->stats.tx_bytes += send_length;
     
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 /**
index 479d5b4..434d940 100644 (file)
@@ -865,7 +865,7 @@ static int fjn_start_xmit(struct sk_buff *skb, struct net_device *dev)
     if (length < ETH_ZLEN)
     {
        if (skb_padto(skb, ETH_ZLEN))
-               return 0;
+               return NETDEV_TX_OK;
        length = ETH_ZLEN;
     }
 
@@ -924,7 +924,7 @@ static int fjn_start_xmit(struct sk_buff *skb, struct net_device *dev)
     }
     dev_kfree_skb (skb);
 
-    return 0;
+    return NETDEV_TX_OK;
 } /* fjn_start_xmit */
 
 /*====================================================================*/
index 02ef63e..0f8118a 100644 (file)
@@ -990,7 +990,7 @@ static int mace_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
   dev_kfree_skb(skb);
 
-  return 0;
+  return NETDEV_TX_OK;
 } /* mace_start_xmit */
 
 /* ----------------------------------------------------------------------------
index 37e05d3..2f39244 100644 (file)
@@ -1399,7 +1399,7 @@ static int smc_start_xmit(struct sk_buff *skb, struct net_device *dev)
        dev_kfree_skb (skb);
        smc->saved_skb = NULL;
        dev->stats.tx_dropped++;
-       return 0;               /* Do not re-queue this packet. */
+       return NETDEV_TX_OK;            /* Do not re-queue this packet. */
     }
     /* A packet is now waiting. */
     smc->packets_waiting++;
@@ -1422,7 +1422,7 @@ static int smc_start_xmit(struct sk_buff *skb, struct net_device *dev)
            outw((ir&0xff00) | IM_ALLOC_INT, ioaddr + INTERRUPT);
            smc_hardware_send_packet(dev);      /* Send the packet now.. */
            spin_unlock_irqrestore(&smc->lock, flags);
-           return 0;
+           return NETDEV_TX_OK;
        }
     }
 
@@ -1431,7 +1431,7 @@ static int smc_start_xmit(struct sk_buff *skb, struct net_device *dev)
     outw((IM_ALLOC_INT << 8) | (ir & 0xff00), ioaddr + INTERRUPT);
     spin_unlock_irqrestore(&smc->lock, flags);
 
-    return 0;
+    return NETDEV_TX_OK;
 }
 
 /*======================================================================
index ef37d22..eda7bf6 100644 (file)
@@ -1384,7 +1384,7 @@ do_start_xmit(struct sk_buff *skb, struct net_device *dev)
     if (pktlen < ETH_ZLEN)
     {
         if (skb_padto(skb, ETH_ZLEN))
-               return 0;
+               return NETDEV_TX_OK;
        pktlen = ETH_ZLEN;
     }
 
@@ -1414,7 +1414,7 @@ do_start_xmit(struct sk_buff *skb, struct net_device *dev)
     dev->trans_start = jiffies;
     dev->stats.tx_bytes += pktlen;
     netif_start_queue(dev);
-    return 0;
+    return NETDEV_TX_OK;
 }
 
 /****************
index 1c35e1d..955a87a 100644 (file)
@@ -2536,7 +2536,7 @@ static int pcnet32_start_xmit(struct sk_buff *skb, struct net_device *dev)
                netif_stop_queue(dev);
        }
        spin_unlock_irqrestore(&lp->lock, flags);
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 /* The PCNET32 interrupt handler. */
index de9cf51..d5d8e1c 100644 (file)
@@ -56,6 +56,12 @@ config BROADCOM_PHY
          Currently supports the BCM5411, BCM5421, BCM5461, BCM5464, BCM5481
          and BCM5482 PHYs.
 
+config BCM63XX_PHY
+       tristate "Drivers for Broadcom 63xx SOCs internal PHY"
+       depends on BCM63XX
+       ---help---
+         Currently supports the 6348 and 6358 PHYs.
+
 config ICPLUS_PHY
        tristate "Drivers for ICPlus PHYs"
        ---help---
index 3a1bfef..edfaac4 100644 (file)
@@ -11,6 +11,7 @@ obj-$(CONFIG_QSEMI_PHY)               += qsemi.o
 obj-$(CONFIG_SMSC_PHY)         += smsc.o
 obj-$(CONFIG_VITESSE_PHY)      += vitesse.o
 obj-$(CONFIG_BROADCOM_PHY)     += broadcom.o
+obj-$(CONFIG_BCM63XX_PHY)      += bcm63xx.o
 obj-$(CONFIG_ICPLUS_PHY)       += icplus.o
 obj-$(CONFIG_REALTEK_PHY)      += realtek.o
 obj-$(CONFIG_LSI_ET1011C_PHY)  += et1011c.o
diff --git a/drivers/net/phy/bcm63xx.c b/drivers/net/phy/bcm63xx.c
new file mode 100644 (file)
index 0000000..4fed95e
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+ *     Driver for Broadcom 63xx SOCs integrated PHYs
+ *
+ *     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/module.h>
+#include <linux/phy.h>
+
+#define MII_BCM63XX_IR         0x1a    /* interrupt register */
+#define MII_BCM63XX_IR_EN      0x4000  /* global interrupt enable */
+#define MII_BCM63XX_IR_DUPLEX  0x0800  /* duplex changed */
+#define MII_BCM63XX_IR_SPEED   0x0400  /* speed changed */
+#define MII_BCM63XX_IR_LINK    0x0200  /* link changed */
+#define MII_BCM63XX_IR_GMASK   0x0100  /* global interrupt mask */
+
+MODULE_DESCRIPTION("Broadcom 63xx internal PHY driver");
+MODULE_AUTHOR("Maxime Bizon <mbizon@freebox.fr>");
+MODULE_LICENSE("GPL");
+
+static int bcm63xx_config_init(struct phy_device *phydev)
+{
+       int reg, err;
+
+       reg = phy_read(phydev, MII_BCM63XX_IR);
+       if (reg < 0)
+               return reg;
+
+       /* Mask interrupts globally.  */
+       reg |= MII_BCM63XX_IR_GMASK;
+       err = phy_write(phydev, MII_BCM63XX_IR, reg);
+       if (err < 0)
+               return err;
+
+       /* Unmask events we are interested in  */
+       reg = ~(MII_BCM63XX_IR_DUPLEX |
+               MII_BCM63XX_IR_SPEED |
+               MII_BCM63XX_IR_LINK) |
+               MII_BCM63XX_IR_EN;
+       err = phy_write(phydev, MII_BCM63XX_IR, reg);
+       if (err < 0)
+               return err;
+       return 0;
+}
+
+static int bcm63xx_ack_interrupt(struct phy_device *phydev)
+{
+       int reg;
+
+       /* Clear pending interrupts.  */
+       reg = phy_read(phydev, MII_BCM63XX_IR);
+       if (reg < 0)
+               return reg;
+
+       return 0;
+}
+
+static int bcm63xx_config_intr(struct phy_device *phydev)
+{
+       int reg, err;
+
+       reg = phy_read(phydev, MII_BCM63XX_IR);
+       if (reg < 0)
+               return reg;
+
+       if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
+               reg &= ~MII_BCM63XX_IR_GMASK;
+       else
+               reg |= MII_BCM63XX_IR_GMASK;
+
+       err = phy_write(phydev, MII_BCM63XX_IR, reg);
+       return err;
+}
+
+static struct phy_driver bcm63xx_1_driver = {
+       .phy_id         = 0x00406000,
+       .phy_id_mask    = 0xfffffc00,
+       .name           = "Broadcom BCM63XX (1)",
+       /* ASYM_PAUSE bit is marked RO in datasheet, so don't cheat */
+       .features       = (PHY_BASIC_FEATURES | SUPPORTED_Pause),
+       .flags          = PHY_HAS_INTERRUPT,
+       .config_init    = bcm63xx_config_init,
+       .config_aneg    = genphy_config_aneg,
+       .read_status    = genphy_read_status,
+       .ack_interrupt  = bcm63xx_ack_interrupt,
+       .config_intr    = bcm63xx_config_intr,
+       .driver         = { .owner = THIS_MODULE },
+};
+
+/* same phy as above, with just a different OUI */
+static struct phy_driver bcm63xx_2_driver = {
+       .phy_id         = 0x002bdc00,
+       .phy_id_mask    = 0xfffffc00,
+       .name           = "Broadcom BCM63XX (2)",
+       .features       = (PHY_BASIC_FEATURES | SUPPORTED_Pause),
+       .flags          = PHY_HAS_INTERRUPT,
+       .config_init    = bcm63xx_config_init,
+       .config_aneg    = genphy_config_aneg,
+       .read_status    = genphy_read_status,
+       .ack_interrupt  = bcm63xx_ack_interrupt,
+       .config_intr    = bcm63xx_config_intr,
+       .driver         = { .owner = THIS_MODULE },
+};
+
+static int __init bcm63xx_phy_init(void)
+{
+       int ret;
+
+       ret = phy_driver_register(&bcm63xx_1_driver);
+       if (ret)
+               goto out_63xx_1;
+       ret = phy_driver_register(&bcm63xx_2_driver);
+       if (ret)
+               goto out_63xx_2;
+       return ret;
+
+out_63xx_2:
+       phy_driver_unregister(&bcm63xx_1_driver);
+out_63xx_1:
+       return ret;
+}
+
+static void __exit bcm63xx_phy_exit(void)
+{
+       phy_driver_unregister(&bcm63xx_1_driver);
+       phy_driver_unregister(&bcm63xx_2_driver);
+}
+
+module_init(bcm63xx_phy_init);
+module_exit(bcm63xx_phy_exit);
index 2ca8b0d..00487f5 100644 (file)
@@ -990,7 +990,7 @@ plip_tx_packet(struct sk_buff *skb, struct net_device *dev)
        schedule_work(&nl->immediate);
        spin_unlock_irq(&nl->lock);
 
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 static void
index 639d11b..d0b9655 100644 (file)
@@ -988,12 +988,12 @@ ppp_start_xmit(struct sk_buff *skb, struct net_device *dev)
        netif_stop_queue(dev);
        skb_queue_tail(&ppp->file.xq, skb);
        ppp_xmit_process(ppp);
-       return 0;
+       return NETDEV_TX_OK;
 
  outf:
        kfree_skb(skb);
        ++dev->stats.tx_dropped;
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 static int
index 961b539..840677f 100644 (file)
@@ -1115,13 +1115,13 @@ static int __devinit r6040_init_one(struct pci_dev *pdev,
        }
 
        /* IO Size check */
-       if (pci_resource_len(pdev, 0) < io_size) {
+       if (pci_resource_len(pdev, bar) < io_size) {
                printk(KERN_ERR DRV_NAME ": Insufficient PCI resources, aborting\n");
                err = -EIO;
                goto err_out;
        }
 
-       pioaddr = pci_resource_start(pdev, 0);  /* IO map base address */
+       pioaddr = pci_resource_start(pdev, bar);        /* IO map base address */
        pci_set_master(pdev);
 
        dev = alloc_etherdev(sizeof(struct r6040_private));
index 8702e7a..bc98e7f 100644 (file)
@@ -114,11 +114,6 @@ static int rionet_rx_clean(struct net_device *ndev)
 
                if (error == NET_RX_DROP) {
                        ndev->stats.rx_dropped++;
-               } else if (error == NET_RX_BAD) {
-                       if (netif_msg_rx_err(rnet))
-                               printk(KERN_WARNING "%s: bad rx packet\n",
-                                      DRV_NAME);
-                       ndev->stats.rx_errors++;
                } else {
                        ndev->stats.rx_packets++;
                        ndev->stats.rx_bytes += RIO_MAX_MSG_SIZE;
@@ -208,7 +203,7 @@ static int rionet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 
        spin_unlock_irqrestore(&rnet->tx_lock, flags);
 
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 static void rionet_dbell_event(struct rio_mport *mport, void *dev_id, u16 sid, u16 tid,
index 81dbcbb..d955346 100644 (file)
@@ -1466,7 +1466,7 @@ static int rr_start_xmit(struct sk_buff *skb, struct net_device *dev)
        spin_unlock_irqrestore(&rrpriv->lock, flags);
 
        dev->trans_start = jiffies;
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 
index 458daa0..d4df933 100644 (file)
@@ -4111,14 +4111,14 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
        if (unlikely(skb->len <= 0)) {
                DBG_PRINT(TX_DBG, "%s:Buffer has no data..\n", dev->name);
                dev_kfree_skb_any(skb);
-               return 0;
+               return NETDEV_TX_OK;
        }
 
        if (!is_s2io_card_up(sp)) {
                DBG_PRINT(TX_DBG, "%s: Card going down for reset\n",
                          dev->name);
                dev_kfree_skb(skb);
-               return 0;
+               return NETDEV_TX_OK;
        }
 
        queue = 0;
@@ -4192,7 +4192,7 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
                s2io_stop_tx_queue(sp, fifo->fifo_no);
                dev_kfree_skb(skb);
                spin_unlock_irqrestore(&fifo->tx_lock, flags);
-               return 0;
+               return NETDEV_TX_OK;
        }
 
        offload_type = s2io_offload_type(skb);
@@ -4304,14 +4304,14 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
        if (sp->config.intr_type == MSI_X)
                tx_intr_handler(fifo);
 
-       return 0;
+       return NETDEV_TX_OK;
 pci_map_failed:
        stats->pci_map_fail_cnt++;
        s2io_stop_tx_queue(sp, fifo->fifo_no);
        stats->mem_freed += skb->truesize;
        dev_kfree_skb(skb);
        spin_unlock_irqrestore(&fifo->tx_lock, flags);
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 static void
index fc0e38b..6a81aec 100644 (file)
@@ -1086,7 +1086,7 @@ sb1000_start_xmit(struct sk_buff *skb, struct net_device *dev)
        printk(KERN_WARNING "%s: trying to transmit!!!\n", dev->name);
        /* sb1000 can't xmit datagrams */
        dev_kfree_skb(skb);
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 /* SB1000 interrupt handler. */
index d8c9cf1..508551f 100644 (file)
@@ -2091,7 +2091,7 @@ static int sbmac_start_tx(struct sk_buff *skb, struct net_device *dev)
 
        spin_unlock_irqrestore(&sc->sbm_lock, flags);
 
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 /**********************************************************************
@@ -2688,7 +2688,7 @@ static int sbmac_poll(struct napi_struct *napi, int budget)
 }
 
 
-static int __init sbmac_probe(struct platform_device *pldev)
+static int __devinit sbmac_probe(struct platform_device *pldev)
 {
        struct net_device *dev;
        struct sbmac_softc *sc;
index ebbbe09..7cc8bb8 100644 (file)
@@ -401,7 +401,7 @@ static int seeq8005_send_packet(struct sk_buff *skb, struct net_device *dev)
 
        if (length < ETH_ZLEN) {
                if (skb_padto(skb, ETH_ZLEN))
-                       return 0;
+                       return NETDEV_TX_OK;
                length = ETH_ZLEN;
        }
        buf = skb->data;
@@ -415,7 +415,7 @@ static int seeq8005_send_packet(struct sk_buff *skb, struct net_device *dev)
        dev_kfree_skb (skb);
        /* You might need to clean up and record Tx statistics here. */
 
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 /*
index 5fb88ca..ecf3279 100644 (file)
@@ -594,7 +594,7 @@ static int sgiseeq_start_xmit(struct sk_buff *skb, struct net_device *dev)
        len = skb->len;
        if (len < ETH_ZLEN) {
                if (skb_padto(skb, ETH_ZLEN))
-                       return 0;
+                       return NETDEV_TX_OK;
                len = ETH_ZLEN;
        }
 
@@ -642,7 +642,7 @@ static int sgiseeq_start_xmit(struct sk_buff *skb, struct net_device *dev)
                netif_stop_queue(dev);
        spin_unlock_irqrestore(&sp->tx_lock, flags);
 
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 static void timeout(struct net_device *dev)
@@ -720,7 +720,7 @@ static const struct net_device_ops sgiseeq_netdev_ops = {
        .ndo_validate_addr      = eth_validate_addr,
 };
 
-static int __init sgiseeq_probe(struct platform_device *pdev)
+static int __devinit sgiseeq_probe(struct platform_device *pdev)
 {
        struct sgiseeq_platform_data *pd = pdev->dev.platform_data;
        struct hpc3_regs *hpcregs = pd->hpc;
index a2d82dd..4c4dcbf 100644 (file)
@@ -1133,7 +1133,7 @@ static int sh_eth_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 
        ndev->trans_start = jiffies;
 
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 /* device close function */
index a9a897b..61ceeaa 100644 (file)
@@ -1628,7 +1628,7 @@ sis900_start_xmit(struct sk_buff *skb, struct net_device *net_dev)
                       "to slot %d.\n",
                       net_dev->name, skb->data, (int)skb->len, entry);
 
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 /**
index 088fe26..888a14a 100644 (file)
@@ -1077,7 +1077,7 @@ static int skfp_send_pkt(struct sk_buff *skb, struct net_device *dev)
                // dequeue packets from xmt queue and send them
                netif_start_queue(dev);
                dev_kfree_skb(skb);
-               return (0);     /* return "success" */
+               return NETDEV_TX_OK;    /* return "success" */
        }
        if (bp->QueueSkb == 0) {        // return with tbusy set: queue full
 
@@ -1091,7 +1091,7 @@ static int skfp_send_pkt(struct sk_buff *skb, struct net_device *dev)
                netif_stop_queue(dev);
        }
        dev->trans_start = jiffies;
-       return 0;
+       return NETDEV_TX_OK;
 
 }                              // skfp_send_pkt
 
index 5c61d5f..899c4a2 100644 (file)
@@ -484,12 +484,12 @@ sl_xmit(struct sk_buff *skb, struct net_device *dev)
                spin_unlock(&sl->lock);
                printk(KERN_WARNING "%s: xmit call when iface is down\n", dev->name);
                dev_kfree_skb(skb);
-               return 0;
+               return NETDEV_TX_OK;
        }
        if (sl->tty == NULL) {
                spin_unlock(&sl->lock);
                dev_kfree_skb(skb);
-               return 0;
+               return NETDEV_TX_OK;
        }
 
        sl_lock(sl);
@@ -498,7 +498,7 @@ sl_xmit(struct sk_buff *skb, struct net_device *dev)
        spin_unlock(&sl->lock);
 
        dev_kfree_skb(skb);
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 
index bc4976a..2a6b6de 100644 (file)
@@ -553,7 +553,7 @@ static int smc911x_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
                dev->stats.tx_dropped++;
                spin_unlock_irqrestore(&lp->lock, flags);
                dev_kfree_skb(skb);
-               return 0;
+               return NETDEV_TX_OK;
        }
 
 #ifdef SMC_USE_DMA
@@ -566,7 +566,7 @@ static int smc911x_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
                        lp->pending_tx_skb = skb;
                        netif_stop_queue(dev);
                        spin_unlock_irqrestore(&lp->lock, flags);
-                       return 0;
+                       return NETDEV_TX_OK;
                } else {
                        DBG(SMC_DEBUG_TX | SMC_DEBUG_DMA, "%s: Activating Tx DMA\n", dev->name);
                        lp->txdma_active = 1;
@@ -577,7 +577,7 @@ static int smc911x_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
        smc911x_hardware_send_pkt(dev);
        spin_unlock_irqrestore(&lp->lock, flags);
 
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 /*
index e02471b..0a1b6f4 100644 (file)
@@ -512,7 +512,7 @@ static int smc_wait_to_send_packet( struct sk_buff * skb, struct net_device * de
        if (length < ETH_ZLEN) {
                if (skb_padto(skb, ETH_ZLEN)) {
                        netif_wake_queue(dev);
-                       return 0;
+                       return NETDEV_TX_OK;
                }
                length = ETH_ZLEN;
        }
@@ -534,7 +534,7 @@ static int smc_wait_to_send_packet( struct sk_buff * skb, struct net_device * de
                lp->saved_skb = NULL;
                /* this IS an error, but, i don't want the skb saved */
                netif_wake_queue(dev);
-               return 0;
+               return NETDEV_TX_OK;
        }
        /* either way, a packet is waiting now */
        lp->packets_waiting++;
@@ -571,12 +571,12 @@ static int smc_wait_to_send_packet( struct sk_buff * skb, struct net_device * de
                SMC_ENABLE_INT( IM_ALLOC_INT );
                PRINTK2((CARDNAME": memory allocation deferred. \n"));
                /* it's deferred, but I'll handle it later */
-               return 0;
+               return NETDEV_TX_OK;
        }
        /* or YES! I can send the packet now.. */
        smc_hardware_send_packet(dev);
        netif_wake_queue(dev);
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 /*
index 1c70e99..0f2c52c 100644 (file)
@@ -655,7 +655,7 @@ static int smc_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
                dev->stats.tx_errors++;
                dev->stats.tx_dropped++;
                dev_kfree_skb(skb);
-               return 0;
+               return NETDEV_TX_OK;
        }
 
        smc_special_lock(&lp->lock);
@@ -692,7 +692,7 @@ static int smc_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
                smc_hardware_send_pkt((unsigned long)dev);
        }
 
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 /*
index 753a1fb..9599ce7 100644 (file)
@@ -211,7 +211,7 @@ static int sonic_send_packet(struct sk_buff *skb, struct net_device *dev)
        length = skb->len;
        if (length < ETH_ZLEN) {
                if (skb_padto(skb, ETH_ZLEN))
-                       return 0;
+                       return NETDEV_TX_OK;
                length = ETH_ZLEN;
        }
 
@@ -265,7 +265,7 @@ static int sonic_send_packet(struct sk_buff *skb, struct net_device *dev)
 
        dev->trans_start = jiffies;
 
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 /*
index 838cce8..1018349 100644 (file)
@@ -1311,7 +1311,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev)
 
        dev->trans_start = jiffies;
 
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 
index 7bb2742..2f1eaaf 100644 (file)
@@ -1015,7 +1015,7 @@ static int sun3_82586_send_packet(struct sk_buff *skb, struct net_device *dev)
        if(skb->len > XMIT_BUFF_SIZE)
        {
                printk("%s: Sorry, max. framelength is %d bytes. The length of your frame is %d bytes.\n",dev->name,XMIT_BUFF_SIZE,skb->len);
-               return 0;
+               return NETDEV_TX_OK;
        }
 
        netif_stop_queue(dev);
@@ -1110,7 +1110,7 @@ static int sun3_82586_send_packet(struct sk_buff *skb, struct net_device *dev)
                dev_kfree_skb(skb);
 #endif
        }
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 /*******************************************
index 534dfe3..0ca4241 100644 (file)
@@ -562,7 +562,7 @@ static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev )
                netif_start_queue(dev);
                dev->trans_start = jiffies;
 
-               return 0;
+               return NETDEV_TX_OK;
        }
 
 
@@ -648,7 +648,7 @@ static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev )
 
        local_irq_restore(flags);
 
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 /* The LANCE interrupt handler. */
index 5017d7f..536cf7e 100644 (file)
@@ -984,7 +984,7 @@ static int bigmac_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
        dev->trans_start = jiffies;
 
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 static struct net_device_stats *bigmac_get_stats(struct net_device *dev)
index 545f81b..0df6332 100644 (file)
@@ -1091,7 +1091,7 @@ start_tx (struct sk_buff *skb, struct net_device *dev)
                        "%s: Transmit frame #%d queued in slot %d.\n",
                        dev->name, np->cur_tx, entry);
        }
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 /* Reset hardware tx and free all of tx buffers */
index 4ef7291..008bd59 100644 (file)
@@ -2338,7 +2338,7 @@ static int happy_meal_start_xmit(struct sk_buff *skb, struct net_device *dev)
        dev->trans_start = jiffies;
 
        tx_add_log(hp, TXLOG_ACTION_TXMIT, 0);
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 static struct net_device_stats *happy_meal_get_stats(struct net_device *dev)
index afc7b35..9d6fd47 100644 (file)
@@ -1163,7 +1163,7 @@ static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev)
        dev->trans_start = jiffies;
        dev_kfree_skb(skb);
 
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 /* taken from the depca driver */
index c6ec61e..dcefb60 100644 (file)
@@ -621,7 +621,7 @@ static int qe_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
        dev_kfree_skb(skb);
 
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 static void qe_set_multicast(struct net_device *dev)
index d737f6b..1ce2da1 100644 (file)
@@ -1509,7 +1509,7 @@ static int tc35815_send_packet(struct sk_buff *skb, struct net_device *dev)
         */
 
        spin_unlock_irqrestore(&lp->lock, flags);
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 #define FATAL_ERROR_INT \
index 384cb5e..70c9ec4 100644 (file)
@@ -1095,11 +1095,11 @@ static int TLan_StartTx( struct sk_buff *skb, struct net_device *dev )
                TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT:  %s PHY is not ready\n",
                          dev->name );
                dev_kfree_skb_any(skb);
-               return 0;
+               return NETDEV_TX_OK;
        }
 
        if (skb_padto(skb, TLAN_MIN_FRAME_SIZE))
-               return 0;
+               return NETDEV_TX_OK;
        txlen = max(skb->len, (unsigned int)TLAN_MIN_FRAME_SIZE);
 
        tail_list = priv->txList + priv->txTail;
@@ -1150,7 +1150,7 @@ static int TLan_StartTx( struct sk_buff *skb, struct net_device *dev )
        CIRC_INC( priv->txTail, TLAN_NUM_TX_LISTS );
 
        dev->trans_start = jiffies;
-       return 0;
+       return NETDEV_TX_OK;
 
 } /* TLan_StartTx */
 
index b40b6de..1787d52 100644 (file)
@@ -1240,7 +1240,7 @@ static int xl_xmit(struct sk_buff *skb, struct net_device *dev)
 
                spin_unlock_irqrestore(&xl_priv->xl_lock,flags) ; 
  
-               return 0;
+               return NETDEV_TX_OK;
        } else {
                spin_unlock_irqrestore(&xl_priv->xl_lock,flags) ; 
                return NETDEV_TX_BUSY;
index 9d89611..6472ba5 100644 (file)
@@ -1041,7 +1041,7 @@ static int tok_send_packet(struct sk_buff *skb, struct net_device *dev)
        writeb(CMD_IN_SRB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD);
        spin_unlock_irqrestore(&(ti->lock), flags);
        dev->trans_start = jiffies;
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 /*****************************************************************************/
index b3715ef..d07e61a 100644 (file)
@@ -1183,7 +1183,7 @@ static int streamer_xmit(struct sk_buff *skb, struct net_device *dev)
 
                streamer_priv->tx_ring_free = (streamer_priv->tx_ring_free + 1) & (STREAMER_TX_RING_SIZE - 1);
                spin_unlock_irqrestore(&streamer_priv->streamer_lock,flags);
-               return 0;
+               return NETDEV_TX_OK;
        } else {
                netif_stop_queue(dev);
                spin_unlock_irqrestore(&streamer_priv->streamer_lock,flags);
index 451b541..f73f4e6 100644 (file)
@@ -1052,7 +1052,7 @@ static int olympic_xmit(struct sk_buff *skb, struct net_device *dev)
                writew((((readw(olympic_mmio+TXENQ_1)) & 0x8000) ^ 0x8000) | 1,olympic_mmio+TXENQ_1);
                netif_wake_queue(dev);
                spin_unlock_irqrestore(&olympic_priv->olympic_lock,flags);
-               return 0;
+               return NETDEV_TX_OK;
        } else {
                spin_unlock_irqrestore(&olympic_priv->olympic_lock,flags);
                return NETDEV_TX_BUSY;
index 54ad4ed..6515894 100644 (file)
@@ -4609,7 +4609,7 @@ static int smctr_send_packet(struct sk_buff *skb, struct net_device *dev)
         if(tp->QueueSkb > 0)
                netif_wake_queue(dev);
                
-        return (0);
+        return NETDEV_TX_OK;
 }
 
 static int smctr_send_lobe_media_test(struct net_device *dev)
index a2eab72..07f6dfd 100644 (file)
@@ -682,7 +682,7 @@ static int tms380tr_hardware_send_packet(struct sk_buff *skb, struct net_device
        tms380tr_exec_sifcmd(dev, CMD_TX_VALID);
        spin_unlock_irqrestore(&tp->lock, flags);
 
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 /*
index 81f054d..769af55 100644 (file)
@@ -651,7 +651,7 @@ static int de_start_xmit (struct sk_buff *skb, struct net_device *dev)
        dw32(TxPoll, NormalTxPoll);
        dev->trans_start = jiffies;
 
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 /* Set or clear the multicast filter for this adaptor.
index 8e78f00..5e15fab 100644 (file)
@@ -676,7 +676,7 @@ static int dmfe_start_xmit(struct sk_buff *skb, struct DEVICE *dev)
        if (skb->len > MAX_PACKET_SIZE) {
                printk(KERN_ERR DRV_NAME ": big packet = %d\n", (u16)skb->len);
                dev_kfree_skb(skb);
-               return 0;
+               return NETDEV_TX_OK;
        }
 
        spin_lock_irqsave(&db->lock, flags);
@@ -722,7 +722,7 @@ static int dmfe_start_xmit(struct sk_buff *skb, struct DEVICE *dev)
        /* free this SKB */
        dev_kfree_skb(skb);
 
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 
index 2abb5d3..9d46638 100644 (file)
@@ -690,7 +690,7 @@ tulip_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
        dev->trans_start = jiffies;
 
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 static void tulip_clean_tx_ring(struct tulip_private *tp)
index 9277ce8..9074a34 100644 (file)
@@ -582,7 +582,7 @@ static int uli526x_start_xmit(struct sk_buff *skb, struct net_device *dev)
        if (skb->len > MAX_PACKET_SIZE) {
                printk(KERN_ERR DRV_NAME ": big packet = %d\n", (u16)skb->len);
                dev_kfree_skb(skb);
-               return 0;
+               return NETDEV_TX_OK;
        }
 
        spin_lock_irqsave(&db->lock, flags);
@@ -624,7 +624,7 @@ static int uli526x_start_xmit(struct sk_buff *skb, struct net_device *dev)
        /* free this SKB */
        dev_kfree_skb(skb);
 
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 
index 842b1a2..6bc7540 100644 (file)
@@ -1058,7 +1058,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev)
                printk(KERN_DEBUG "%s: Transmit frame #%d queued in slot %d.\n",
                           dev->name, np->cur_tx, entry);
        }
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 static void netdev_tx_done(struct net_device *dev)
index c2ca9f4..22b6a23 100644 (file)
@@ -434,7 +434,7 @@ static int xircom_start_xmit(struct sk_buff *skb, struct net_device *dev)
                        card->transmit_used = nextdescriptor;
                        leave("xircom-start_xmit - sent");
                        spin_unlock_irqrestore(&card->lock,flags);
-                       return 0;
+                       return NETDEV_TX_OK;
        }
 
 
index 027f7ab..a998b6a 100644 (file)
@@ -398,12 +398,12 @@ static int tun_net_xmit(struct sk_buff *skb, struct net_device *dev)
        if (tun->flags & TUN_FASYNC)
                kill_fasync(&tun->fasync, SIGIO, POLL_IN);
        wake_up_interruptible(&tun->socket.wait);
-       return 0;
+       return NETDEV_TX_OK;
 
 drop:
        dev->stats.tx_dropped++;
        kfree_skb(skb);
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 static void tun_net_mclist(struct net_device *dev)
@@ -641,6 +641,9 @@ static __inline__ ssize_t tun_get_user(struct tun_struct *tun,
                case VIRTIO_NET_HDR_GSO_TCPV6:
                        skb_shinfo(skb)->gso_type = SKB_GSO_TCPV6;
                        break;
+               case VIRTIO_NET_HDR_GSO_UDP:
+                       skb_shinfo(skb)->gso_type = SKB_GSO_UDP;
+                       break;
                default:
                        tun->dev->stats.rx_frame_errors++;
                        kfree_skb(skb);
@@ -726,6 +729,8 @@ static __inline__ ssize_t tun_put_user(struct tun_struct *tun,
                                gso.gso_type = VIRTIO_NET_HDR_GSO_TCPV4;
                        else if (sinfo->gso_type & SKB_GSO_TCPV6)
                                gso.gso_type = VIRTIO_NET_HDR_GSO_TCPV6;
+                       else if (sinfo->gso_type & SKB_GSO_UDP)
+                               gso.gso_type = VIRTIO_NET_HDR_GSO_UDP;
                        else
                                BUG();
                        if (sinfo->gso_type & SKB_GSO_TCP_ECN)
@@ -997,7 +1002,6 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
                                goto err_free_sk;
                }
 
-               err = -EINVAL;
                err = register_netdevice(tun->dev);
                if (err < 0)
                        goto err_free_sk;
@@ -1074,7 +1078,8 @@ static int set_offload(struct net_device *dev, unsigned long arg)
        old_features = dev->features;
        /* Unset features, set them as we chew on the arg. */
        features = (old_features & ~(NETIF_F_HW_CSUM|NETIF_F_SG|NETIF_F_FRAGLIST
-                                   |NETIF_F_TSO_ECN|NETIF_F_TSO|NETIF_F_TSO6));
+                                   |NETIF_F_TSO_ECN|NETIF_F_TSO|NETIF_F_TSO6
+                                   |NETIF_F_UFO));
 
        if (arg & TUN_F_CSUM) {
                features |= NETIF_F_HW_CSUM|NETIF_F_SG|NETIF_F_FRAGLIST;
@@ -1091,6 +1096,11 @@ static int set_offload(struct net_device *dev, unsigned long arg)
                                features |= NETIF_F_TSO6;
                        arg &= ~(TUN_F_TSO4|TUN_F_TSO6);
                }
+
+               if (arg & TUN_F_UFO) {
+                       features |= NETIF_F_UFO;
+                       arg &= ~TUN_F_UFO;
+               }
        }
 
        /* This gives the user a way to test for new features in future by
index cf25eb4..2c26b45 100644 (file)
@@ -909,7 +909,7 @@ typhoon_start_tx(struct sk_buff *skb, struct net_device *dev)
                        netif_wake_queue(dev);
        }
 
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 static void
index 3b957e6..52a6750 100644 (file)
@@ -209,9 +209,10 @@ static struct sk_buff *get_new_skb(struct ucc_geth_private *ugeth,
 {
        struct sk_buff *skb = NULL;
 
-       skb = dev_alloc_skb(ugeth->ug_info->uf_info.max_rx_buf_length +
-                                 UCC_GETH_RX_DATA_BUF_ALIGNMENT);
-
+       skb = __skb_dequeue(&ugeth->rx_recycle);
+       if (!skb)
+               skb = dev_alloc_skb(ugeth->ug_info->uf_info.max_rx_buf_length +
+                                   UCC_GETH_RX_DATA_BUF_ALIGNMENT);
        if (skb == NULL)
                return NULL;
 
@@ -1986,6 +1987,8 @@ static void ucc_geth_memclean(struct ucc_geth_private *ugeth)
                iounmap(ugeth->ug_regs);
                ugeth->ug_regs = NULL;
        }
+
+       skb_queue_purge(&ugeth->rx_recycle);
 }
 
 static void ucc_geth_set_multi(struct net_device *dev)
@@ -2202,6 +2205,8 @@ static int ucc_struct_init(struct ucc_geth_private *ugeth)
                return -ENOMEM;
        }
 
+       skb_queue_head_init(&ugeth->rx_recycle);
+
        return 0;
 }
 
@@ -3173,7 +3178,7 @@ static int ucc_geth_start_xmit(struct sk_buff *skb, struct net_device *dev)
 #endif
        spin_unlock_irq(&ugeth->lock);
 
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 static int ucc_geth_rx(struct ucc_geth_private *ugeth, u8 rxQ, int rx_work_limit)
@@ -3208,8 +3213,10 @@ static int ucc_geth_rx(struct ucc_geth_private *ugeth, u8 rxQ, int rx_work_limit
                        if (netif_msg_rx_err(ugeth))
                                ugeth_err("%s, %d: ERROR!!! skb - 0x%08x",
                                           __func__, __LINE__, (u32) skb);
-                       if (skb)
-                               dev_kfree_skb_any(skb);
+                       if (skb) {
+                               skb->data = skb->head + NET_SKB_PAD;
+                               __skb_queue_head(&ugeth->rx_recycle, skb);
+                       }
 
                        ugeth->rx_skbuff[rxQ][ugeth->skb_currx[rxQ]] = NULL;
                        dev->stats.rx_dropped++;
@@ -3267,6 +3274,8 @@ static int ucc_geth_tx(struct net_device *dev, u8 txQ)
 
        /* Normal processing. */
        while ((bd_status & T_R) == 0) {
+               struct sk_buff *skb;
+
                /* BD contains already transmitted buffer.   */
                /* Handle the transmitted buffer and release */
                /* the BD to be used with the current frame  */
@@ -3276,9 +3285,16 @@ static int ucc_geth_tx(struct net_device *dev, u8 txQ)
 
                dev->stats.tx_packets++;
 
-               /* Free the sk buffer associated with this TxBD */
-               dev_kfree_skb(ugeth->
-                                 tx_skbuff[txQ][ugeth->skb_dirtytx[txQ]]);
+               skb = ugeth->tx_skbuff[txQ][ugeth->skb_dirtytx[txQ]];
+
+               if (skb_queue_len(&ugeth->rx_recycle) < RX_BD_RING_LEN &&
+                            skb_recycle_check(skb,
+                                   ugeth->ug_info->uf_info.max_rx_buf_length +
+                                   UCC_GETH_RX_DATA_BUF_ALIGNMENT))
+                       __skb_queue_head(&ugeth->rx_recycle, skb);
+               else
+                       dev_kfree_skb(skb);
+
                ugeth->tx_skbuff[txQ][ugeth->skb_dirtytx[txQ]] = NULL;
                ugeth->skb_dirtytx[txQ] =
                    (ugeth->skb_dirtytx[txQ] +
@@ -3307,16 +3323,16 @@ static int ucc_geth_poll(struct napi_struct *napi, int budget)
 
        ug_info = ugeth->ug_info;
 
-       howmany = 0;
-       for (i = 0; i < ug_info->numQueuesRx; i++)
-               howmany += ucc_geth_rx(ugeth, i, budget - howmany);
-
        /* Tx event processing */
        spin_lock(&ugeth->lock);
        for (i = 0; i < ug_info->numQueuesTx; i++)
                ucc_geth_tx(ugeth->ndev, i);
        spin_unlock(&ugeth->lock);
 
+       howmany = 0;
+       for (i = 0; i < ug_info->numQueuesRx; i++)
+               howmany += ucc_geth_rx(ugeth, i, budget - howmany);
+
        if (howmany < budget) {
                napi_complete(napi);
                setbits32(ugeth->uccf->p_uccm, UCCE_RX_EVENTS | UCCE_TX_EVENTS);
index 195ab26..cfb31af 100644 (file)
@@ -1212,6 +1212,8 @@ struct ucc_geth_private {
        /* index of the first skb which hasn't been transmitted yet. */
        u16 skb_dirtytx[NUM_TX_QUEUES];
 
+       struct sk_buff_head rx_recycle;
+
        struct ugeth_mii_info *mii_info;
        struct phy_device *phydev;
        phy_interface_t phy_interface;
index b9dd425..7abdc4a 100644 (file)
@@ -448,7 +448,7 @@ static int catc_start_xmit(struct sk_buff *skb, struct net_device *netdev)
 
        dev_kfree_skb(skb);
 
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 static void catc_tx_timeout(struct net_device *netdev)
index f8c6d7e..ffe4106 100644 (file)
@@ -780,7 +780,7 @@ static int hso_net_start_xmit(struct sk_buff *skb, struct net_device *net)
        netif_stop_queue(net);
        if (hso_get_activity(odev->parent) == -EAGAIN) {
                odev->skb_tx_buf = skb;
-               return 0;
+               return NETDEV_TX_OK;
        }
 
        /* log if asked */
index 1f9ec29..200fe3d 100644 (file)
@@ -829,7 +829,7 @@ static int kaweth_start_xmit(struct sk_buff *skb, struct net_device *net)
                        kaweth->stats.tx_errors++;
                        netif_start_queue(net);
                        spin_unlock_irq(&kaweth->device_lock);
-                       return 0;
+                       return NETDEV_TX_OK;
                }
        }
 
@@ -864,7 +864,7 @@ skip:
 
        spin_unlock_irq(&kaweth->device_lock);
 
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 /****************************************************************
index 631d269..69d2df9 100644 (file)
@@ -914,7 +914,7 @@ static int pegasus_start_xmit(struct sk_buff *skb, struct net_device *net)
        }
        dev_kfree_skb(skb);
 
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 static struct net_device_stats *pegasus_netdev_stats(struct net_device *dev)
index fcc6fa0..bac8b77 100644 (file)
@@ -753,7 +753,7 @@ static int rtl8150_start_xmit(struct sk_buff *skb, struct net_device *netdev)
                netdev->trans_start = jiffies;
        }
 
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 
index edfd9e1..25e435c 100644 (file)
@@ -575,7 +575,9 @@ EXPORT_SYMBOL_GPL(usbnet_unlink_rx_urbs);
 int usbnet_stop (struct net_device *net)
 {
        struct usbnet           *dev = netdev_priv(net);
+       struct driver_info      *info = dev->driver_info;
        int                     temp;
+       int                     retval;
        DECLARE_WAIT_QUEUE_HEAD_ONSTACK (unlink_wakeup);
        DECLARE_WAITQUEUE (wait, current);
 
@@ -587,6 +589,18 @@ int usbnet_stop (struct net_device *net)
                        net->stats.rx_errors, net->stats.tx_errors
                        );
 
+       /* allow minidriver to stop correctly (wireless devices to turn off
+        * radio etc) */
+       if (info->stop) {
+               retval = info->stop(dev);
+               if (retval < 0 && netif_msg_ifdown(dev))
+                       devinfo(dev,
+                               "stop fail (%d) usbnet usb-%s-%s, %s",
+                               retval,
+                               dev->udev->bus->bus_name, dev->udev->devpath,
+                               info->description);
+       }
+
        // ensure there are no more active urbs
        add_wait_queue (&unlink_wakeup, &wait);
        dev->wait = &unlink_wakeup;
index 1097c72..190f784 100644 (file)
@@ -171,6 +171,7 @@ static int veth_xmit(struct sk_buff *skb, struct net_device *dev)
        if (skb->len > (rcv->mtu + MTU_PAD))
                goto rx_drop;
 
+        skb->tstamp.tv64 = 0;
        skb->pkt_type = PACKET_HOST;
        skb->protocol = eth_type_trans(skb, rcv);
        if (dev->features & NETIF_F_NO_CSUM)
@@ -189,17 +190,17 @@ static int veth_xmit(struct sk_buff *skb, struct net_device *dev)
        rcv_stats->rx_packets++;
 
        netif_rx(skb);
-       return 0;
+       return NETDEV_TX_OK;
 
 tx_drop:
        kfree_skb(skb);
        stats->tx_dropped++;
-       return 0;
+       return NETDEV_TX_OK;
 
 rx_drop:
        kfree_skb(skb);
        rcv_stats->rx_dropped++;
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 /*
index 88c30a5..46eb618 100644 (file)
@@ -1226,7 +1226,7 @@ static int rhine_start_tx(struct sk_buff *skb, struct net_device *dev)
        entry = rp->cur_tx % TX_RING_SIZE;
 
        if (skb_padto(skb, ETH_ZLEN))
-               return 0;
+               return NETDEV_TX_OK;
 
        rp->tx_skbuff[entry] = skb;
 
@@ -1238,7 +1238,7 @@ static int rhine_start_tx(struct sk_buff *skb, struct net_device *dev)
                        dev_kfree_skb(skb);
                        rp->tx_skbuff[entry] = NULL;
                        dev->stats.tx_dropped++;
-                       return 0;
+                       return NETDEV_TX_OK;
                }
 
                /* Padding is not copied and so must be redone. */
@@ -1286,7 +1286,7 @@ static int rhine_start_tx(struct sk_buff *skb, struct net_device *dev)
                printk(KERN_DEBUG "%s: Transmit frame #%d queued in slot %d.\n",
                       dev->name, rp->cur_tx-1, entry);
        }
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 /* The interrupt handler does all of the Rx thread work and cleans up
index 3ba3595..47be41a 100644 (file)
@@ -61,9 +61,9 @@
 #include <linux/interrupt.h>
 #include <linux/string.h>
 #include <linux/wait.h>
-#include <asm/io.h>
+#include <linux/io.h>
 #include <linux/if.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
 #include <linux/proc_fs.h>
 #include <linux/inetdevice.h>
 #include <linux/reboot.h>
@@ -81,7 +81,7 @@
 #include "via-velocity.h"
 
 
-static int velocity_nics = 0;
+static int velocity_nics;
 static int msglevel = MSG_LEVEL_INFO;
 
 /**
@@ -92,8 +92,7 @@ static int msglevel = MSG_LEVEL_INFO;
  *     Fetch the mask bits of the selected CAM and store them into the
  *     provided mask buffer.
  */
-
-static void mac_get_cam_mask(struct mac_regs __iomem * regs, u8 * mask)
+static void mac_get_cam_mask(struct mac_regs __iomem *regs, u8 *mask)
 {
        int i;
 
@@ -111,7 +110,6 @@ static void mac_get_cam_mask(struct mac_regs __iomem * regs, u8 * mask)
 
        /* Select mar */
        BYTE_REG_BITS_SET(CAMCR_PS_MAR, CAMCR_PS1 | CAMCR_PS0, &regs->CAMCR);
-
 }
 
 
@@ -122,8 +120,7 @@ static void mac_get_cam_mask(struct mac_regs __iomem * regs, u8 * mask)
  *
  *     Store a new mask into a CAM
  */
-
-static void mac_set_cam_mask(struct mac_regs __iomem * regs, u8 * mask)
+static void mac_set_cam_mask(struct mac_regs __iomem *regs, u8 *mask)
 {
        int i;
        /* Select CAM mask */
@@ -131,9 +128,9 @@ static void mac_set_cam_mask(struct mac_regs __iomem * regs, u8 * mask)
 
        writeb(CAMADDR_CAMEN, &regs->CAMADDR);
 
-       for (i = 0; i < 8; i++) {
+       for (i = 0; i < 8; i++)
                writeb(*mask++, &(regs->MARCAM[i]));
-       }
+
        /* disable CAMEN */
        writeb(0, &regs->CAMADDR);
 
@@ -141,7 +138,7 @@ static void mac_set_cam_mask(struct mac_regs __iomem * regs, u8 * mask)
        BYTE_REG_BITS_SET(CAMCR_PS_MAR, CAMCR_PS1 | CAMCR_PS0, &regs->CAMCR);
 }
 
-static void mac_set_vlan_cam_mask(struct mac_regs __iomem * regs, u8 * mask)
+static void mac_set_vlan_cam_mask(struct mac_regs __iomem *regs, u8 *mask)
 {
        int i;
        /* Select CAM mask */
@@ -149,9 +146,9 @@ static void mac_set_vlan_cam_mask(struct mac_regs __iomem * regs, u8 * mask)
 
        writeb(CAMADDR_CAMEN | CAMADDR_VCAMSL, &regs->CAMADDR);
 
-       for (i = 0; i < 8; i++) {
+       for (i = 0; i < 8; i++)
                writeb(*mask++, &(regs->MARCAM[i]));
-       }
+
        /* disable CAMEN */
        writeb(0, &regs->CAMADDR);
 
@@ -167,8 +164,7 @@ static void mac_set_vlan_cam_mask(struct mac_regs __iomem * regs, u8 * mask)
  *
  *     Load an address or vlan tag into a CAM
  */
-
-static void mac_set_cam(struct mac_regs __iomem * regs, int idx, const u8 *addr)
+static void mac_set_cam(struct mac_regs __iomem *regs, int idx, const u8 *addr)
 {
        int i;
 
@@ -179,9 +175,9 @@ static void mac_set_cam(struct mac_regs __iomem * regs, int idx, const u8 *addr)
 
        writeb(CAMADDR_CAMEN | idx, &regs->CAMADDR);
 
-       for (i = 0; i < 6; i++) {
+       for (i = 0; i < 6; i++)
                writeb(*addr++, &(regs->MARCAM[i]));
-       }
+
        BYTE_REG_BITS_ON(CAMCR_CAMWR, &regs->CAMCR);
 
        udelay(10);
@@ -192,7 +188,7 @@ static void mac_set_cam(struct mac_regs __iomem * regs, int idx, const u8 *addr)
        BYTE_REG_BITS_SET(CAMCR_PS_MAR, CAMCR_PS1 | CAMCR_PS0, &regs->CAMCR);
 }
 
-static void mac_set_vlan_cam(struct mac_regs __iomem * regs, int idx,
+static void mac_set_vlan_cam(struct mac_regs __iomem *regs, int idx,
                             const u8 *addr)
 {
 
@@ -223,8 +219,7 @@ static void mac_set_vlan_cam(struct mac_regs __iomem * regs, int idx,
  *     reset the Wake on lan features. This function doesn't restore
  *     the rest of the logic from the result of sleep/wakeup
  */
-
-static void mac_wol_reset(struct mac_regs __iomem * regs)
+static void mac_wol_reset(struct mac_regs __iomem *regs)
 {
 
        /* Turn off SWPTAG right after leaving power mode */
@@ -242,7 +237,6 @@ static void mac_wol_reset(struct mac_regs __iomem * regs)
        writew(0xFFFF, &regs->WOLSRClr);
 }
 
-static int velocity_mii_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
 static const struct ethtool_ops velocity_ethtool_ops;
 
 /*
@@ -253,10 +247,10 @@ MODULE_AUTHOR("VIA Networking Technologies, Inc.");
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("VIA Networking Velocity Family Gigabit Ethernet Adapter Driver");
 
-#define VELOCITY_PARAM(N,D) \
-        static int N[MAX_UNITS]=OPTION_DEFAULT;\
+#define VELOCITY_PARAM(N, D) \
+       static int N[MAX_UNITS] = OPTION_DEFAULT;\
        module_param_array(N, int, NULL, 0); \
-        MODULE_PARM_DESC(N, D);
+       MODULE_PARM_DESC(N, D);
 
 #define RX_DESC_MIN     64
 #define RX_DESC_MAX     255
@@ -336,8 +330,8 @@ VELOCITY_PARAM(flow_control, "Enable flow control ability");
    4: indicate 10Mbps full duplex mode
 
    Note:
-        if EEPROM have been set to the force mode, this option is ignored
-            by driver.
+   if EEPROM have been set to the force mode, this option is ignored
+   by driver.
 */
 VELOCITY_PARAM(speed_duplex, "Setting the speed and duplex mode");
 
@@ -370,76 +364,14 @@ static int rx_copybreak = 200;
 module_param(rx_copybreak, int, 0644);
 MODULE_PARM_DESC(rx_copybreak, "Copy breakpoint for copy-only-tiny-frames");
 
-static void velocity_init_info(struct pci_dev *pdev, struct velocity_info *vptr,
-                              const struct velocity_info_tbl *info);
-static int velocity_get_pci_info(struct velocity_info *, struct pci_dev *pdev);
-static void velocity_print_info(struct velocity_info *vptr);
-static int velocity_open(struct net_device *dev);
-static int velocity_change_mtu(struct net_device *dev, int mtu);
-static int velocity_xmit(struct sk_buff *skb, struct net_device *dev);
-static irqreturn_t velocity_intr(int irq, void *dev_instance);
-static void velocity_set_multi(struct net_device *dev);
-static struct net_device_stats *velocity_get_stats(struct net_device *dev);
-static int velocity_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
-static int velocity_close(struct net_device *dev);
-static int velocity_receive_frame(struct velocity_info *, int idx);
-static int velocity_alloc_rx_buf(struct velocity_info *, int idx);
-static void velocity_free_rd_ring(struct velocity_info *vptr);
-static void velocity_free_tx_buf(struct velocity_info *vptr, struct velocity_td_info *);
-static int velocity_soft_reset(struct velocity_info *vptr);
-static void mii_init(struct velocity_info *vptr, u32 mii_status);
-static u32 velocity_get_link(struct net_device *dev);
-static u32 velocity_get_opt_media_mode(struct velocity_info *vptr);
-static void velocity_print_link_status(struct velocity_info *vptr);
-static void safe_disable_mii_autopoll(struct mac_regs __iomem * regs);
-static void velocity_shutdown(struct velocity_info *vptr);
-static void enable_flow_control_ability(struct velocity_info *vptr);
-static void enable_mii_autopoll(struct mac_regs __iomem * regs);
-static int velocity_mii_read(struct mac_regs __iomem *, u8 byIdx, u16 * pdata);
-static int velocity_mii_write(struct mac_regs __iomem *, u8 byMiiAddr, u16 data);
-static u32 mii_check_media_mode(struct mac_regs __iomem * regs);
-static u32 check_connection_type(struct mac_regs __iomem * regs);
-static int velocity_set_media_mode(struct velocity_info *vptr, u32 mii_status);
-
 #ifdef CONFIG_PM
-
-static int velocity_suspend(struct pci_dev *pdev, pm_message_t state);
-static int velocity_resume(struct pci_dev *pdev);
-
 static DEFINE_SPINLOCK(velocity_dev_list_lock);
 static LIST_HEAD(velocity_dev_list);
-
-#endif
-
-#if defined(CONFIG_PM) && defined(CONFIG_INET)
-
-static int velocity_netdev_event(struct notifier_block *nb, unsigned long notification, void *ptr);
-
-static struct notifier_block velocity_inetaddr_notifier = {
-      .notifier_call   = velocity_netdev_event,
-};
-
-static void velocity_register_notifier(void)
-{
-       register_inetaddr_notifier(&velocity_inetaddr_notifier);
-}
-
-static void velocity_unregister_notifier(void)
-{
-       unregister_inetaddr_notifier(&velocity_inetaddr_notifier);
-}
-
-#else
-
-#define velocity_register_notifier()   do {} while (0)
-#define velocity_unregister_notifier() do {} while (0)
-
 #endif
 
 /*
  *     Internal board variants. At the moment we have only one
  */
-
 static struct velocity_info_tbl chip_info_table[] = {
        {CHIP_TYPE_VT6110, "VIA Networking Velocity Family Gigabit Ethernet Adapter", 1, 0x00FFFFFFUL},
        { }
@@ -449,7 +381,6 @@ static struct velocity_info_tbl chip_info_table[] = {
  *     Describe the PCI device identifiers that we support in this
  *     device driver. Used for hotplug autoloading.
  */
-
 static const struct pci_device_id velocity_id_table[] __devinitdata = {
        { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_612X) },
        { }
@@ -464,7 +395,6 @@ MODULE_DEVICE_TABLE(pci, velocity_id_table);
  *     Given a chip identifier return a suitable description. Returns
  *     a pointer a static string valid while the driver is loaded.
  */
-
 static const char __devinit *get_chip_name(enum chip_type chip_id)
 {
        int i;
@@ -482,7 +412,6 @@ static const char __devinit *get_chip_name(enum chip_type chip_id)
  *     unload for each active device that is present. Disconnects
  *     the device from the network layer and frees all the resources
  */
-
 static void __devexit velocity_remove1(struct pci_dev *pdev)
 {
        struct net_device *dev = pci_get_drvdata(pdev);
@@ -520,7 +449,6 @@ static void __devexit velocity_remove1(struct pci_dev *pdev)
  *     all the verification and checking as well as reporting so that
  *     we don't duplicate code for each option.
  */
-
 static void __devinit velocity_set_int_opt(int *opt, int val, int min, int max, int def, char *name, const char *devname)
 {
        if (val == -1)
@@ -549,8 +477,7 @@ static void __devinit velocity_set_int_opt(int *opt, int val, int min, int max,
  *     all the verification and checking as well as reporting so that
  *     we don't duplicate code for each option.
  */
-
-static void __devinit velocity_set_bool_opt(u32 * opt, int val, int def, u32 flag, char *name, const char *devname)
+static void __devinit velocity_set_bool_opt(u32 *opt, int val, int def, u32 flag, char *name, const char *devname)
 {
        (*opt) &= (~flag);
        if (val == -1)
@@ -575,7 +502,6 @@ static void __devinit velocity_set_bool_opt(u32 * opt, int val, int def, u32 fla
  *     Turn the module and command options into a single structure
  *     for the current device
  */
-
 static void __devinit velocity_get_options(struct velocity_opt *opts, int index, const char *devname)
 {
 
@@ -601,10 +527,9 @@ static void __devinit velocity_get_options(struct velocity_opt *opts, int index,
  *     Initialize the content addressable memory used for filters. Load
  *     appropriately according to the presence of VLAN
  */
-
 static void velocity_init_cam_filter(struct velocity_info *vptr)
 {
-       struct mac_regs __iomem * regs = vptr->mac_regs;
+       struct mac_regs __iomem *regs = vptr->mac_regs;
 
        /* Turn on MCFG_PQEN, turn off MCFG_RTGOPT */
        WORD_REG_BITS_SET(MCFG_PQEN, MCFG_RTGOPT, &regs->MCFG);
@@ -647,19 +572,19 @@ static void velocity_vlan_rx_add_vid(struct net_device *dev, unsigned short vid)
 {
        struct velocity_info *vptr = netdev_priv(dev);
 
-        spin_lock_irq(&vptr->lock);
+       spin_lock_irq(&vptr->lock);
        velocity_init_cam_filter(vptr);
-        spin_unlock_irq(&vptr->lock);
+       spin_unlock_irq(&vptr->lock);
 }
 
 static void velocity_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
 {
        struct velocity_info *vptr = netdev_priv(dev);
 
-        spin_lock_irq(&vptr->lock);
+       spin_lock_irq(&vptr->lock);
        vlan_group_set_device(vptr->vlgrp, vid, NULL);
        velocity_init_cam_filter(vptr);
-        spin_unlock_irq(&vptr->lock);
+       spin_unlock_irq(&vptr->lock);
 }
 
 static void velocity_init_rx_ring_indexes(struct velocity_info *vptr)
@@ -674,11 +599,10 @@ static void velocity_init_rx_ring_indexes(struct velocity_info *vptr)
  *     Reset the ownership and status for the receive ring side.
  *     Hand all the receive queue to the NIC.
  */
-
 static void velocity_rx_reset(struct velocity_info *vptr)
 {
 
-       struct mac_regs __iomem * regs = vptr->mac_regs;
+       struct mac_regs __iomem *regs = vptr->mac_regs;
        int i;
 
        velocity_init_rx_ring_indexes(vptr);
@@ -696,887 +620,844 @@ static void velocity_rx_reset(struct velocity_info *vptr)
 }
 
 /**
- *     velocity_init_registers -       initialise MAC registers
- *     @vptr: velocity to init
- *     @type: type of initialisation (hot or cold)
+ *     velocity_get_opt_media_mode     -       get media selection
+ *     @vptr: velocity adapter
  *
- *     Initialise the MAC on a reset or on first set up on the
- *     hardware.
+ *     Get the media mode stored in EEPROM or module options and load
+ *     mii_status accordingly. The requested link state information
+ *     is also returned.
  */
-
-static void velocity_init_registers(struct velocity_info *vptr,
-                                   enum velocity_init_type type)
+static u32 velocity_get_opt_media_mode(struct velocity_info *vptr)
 {
-       struct mac_regs __iomem * regs = vptr->mac_regs;
-       int i, mii_status;
-
-       mac_wol_reset(regs);
-
-       switch (type) {
-       case VELOCITY_INIT_RESET:
-       case VELOCITY_INIT_WOL:
-
-               netif_stop_queue(vptr->dev);
-
-               /*
-                *      Reset RX to prevent RX pointer not on the 4X location
-                */
-               velocity_rx_reset(vptr);
-               mac_rx_queue_run(regs);
-               mac_rx_queue_wake(regs);
-
-               mii_status = velocity_get_opt_media_mode(vptr);
-               if (velocity_set_media_mode(vptr, mii_status) != VELOCITY_LINK_CHANGE) {
-                       velocity_print_link_status(vptr);
-                       if (!(vptr->mii_status & VELOCITY_LINK_FAIL))
-                               netif_wake_queue(vptr->dev);
-               }
-
-               enable_flow_control_ability(vptr);
-
-               mac_clear_isr(regs);
-               writel(CR0_STOP, &regs->CR0Clr);
-               writel((CR0_DPOLL | CR0_TXON | CR0_RXON | CR0_STRT),
-                                                       &regs->CR0Set);
+       u32 status = 0;
 
+       switch (vptr->options.spd_dpx) {
+       case SPD_DPX_AUTO:
+               status = VELOCITY_AUTONEG_ENABLE;
                break;
+       case SPD_DPX_100_FULL:
+               status = VELOCITY_SPEED_100 | VELOCITY_DUPLEX_FULL;
+               break;
+       case SPD_DPX_10_FULL:
+               status = VELOCITY_SPEED_10 | VELOCITY_DUPLEX_FULL;
+               break;
+       case SPD_DPX_100_HALF:
+               status = VELOCITY_SPEED_100;
+               break;
+       case SPD_DPX_10_HALF:
+               status = VELOCITY_SPEED_10;
+               break;
+       }
+       vptr->mii_status = status;
+       return status;
+}
 
-       case VELOCITY_INIT_COLD:
-       default:
-               /*
-                *      Do reset
-                */
-               velocity_soft_reset(vptr);
-               mdelay(5);
-
-               mac_eeprom_reload(regs);
-               for (i = 0; i < 6; i++) {
-                       writeb(vptr->dev->dev_addr[i], &(regs->PAR[i]));
-               }
-               /*
-                *      clear Pre_ACPI bit.
-                */
-               BYTE_REG_BITS_OFF(CFGA_PACPI, &(regs->CFGA));
-               mac_set_rx_thresh(regs, vptr->options.rx_thresh);
-               mac_set_dma_length(regs, vptr->options.DMA_length);
-
-               writeb(WOLCFG_SAM | WOLCFG_SAB, &regs->WOLCFGSet);
-               /*
-                *      Back off algorithm use original IEEE standard
-                */
-               BYTE_REG_BITS_SET(CFGB_OFSET, (CFGB_CRANDOM | CFGB_CAP | CFGB_MBA | CFGB_BAKOPT), &regs->CFGB);
-
-               /*
-                *      Init CAM filter
-                */
-               velocity_init_cam_filter(vptr);
-
-               /*
-                *      Set packet filter: Receive directed and broadcast address
-                */
-               velocity_set_multi(vptr->dev);
-
-               /*
-                *      Enable MII auto-polling
-                */
-               enable_mii_autopoll(regs);
-
-               vptr->int_mask = INT_MASK_DEF;
-
-               writel(vptr->rx.pool_dma, &regs->RDBaseLo);
-               writew(vptr->options.numrx - 1, &regs->RDCSize);
-               mac_rx_queue_run(regs);
-               mac_rx_queue_wake(regs);
-
-               writew(vptr->options.numtx - 1, &regs->TDCSize);
-
-               for (i = 0; i < vptr->tx.numq; i++) {
-                       writel(vptr->tx.pool_dma[i], &regs->TDBaseLo[i]);
-                       mac_tx_queue_run(regs, i);
-               }
-
-               init_flow_control_register(vptr);
+/**
+ *     safe_disable_mii_autopoll       -       autopoll off
+ *     @regs: velocity registers
+ *
+ *     Turn off the autopoll and wait for it to disable on the chip
+ */
+static void safe_disable_mii_autopoll(struct mac_regs __iomem *regs)
+{
+       u16 ww;
 
-               writel(CR0_STOP, &regs->CR0Clr);
-               writel((CR0_DPOLL | CR0_TXON | CR0_RXON | CR0_STRT), &regs->CR0Set);
+       /*  turn off MAUTO */
+       writeb(0, &regs->MIICR);
+       for (ww = 0; ww < W_MAX_TIMEOUT; ww++) {
+               udelay(1);
+               if (BYTE_REG_BITS_IS_ON(MIISR_MIDLE, &regs->MIISR))
+                       break;
+       }
+}
 
-               mii_status = velocity_get_opt_media_mode(vptr);
-               netif_stop_queue(vptr->dev);
+/**
+ *     enable_mii_autopoll     -       turn on autopolling
+ *     @regs: velocity registers
+ *
+ *     Enable the MII link status autopoll feature on the Velocity
+ *     hardware. Wait for it to enable.
+ */
+static void enable_mii_autopoll(struct mac_regs __iomem *regs)
+{
+       int ii;
 
-               mii_init(vptr, mii_status);
+       writeb(0, &(regs->MIICR));
+       writeb(MIIADR_SWMPL, &regs->MIIADR);
 
-               if (velocity_set_media_mode(vptr, mii_status) != VELOCITY_LINK_CHANGE) {
-                       velocity_print_link_status(vptr);
-                       if (!(vptr->mii_status & VELOCITY_LINK_FAIL))
-                               netif_wake_queue(vptr->dev);
-               }
+       for (ii = 0; ii < W_MAX_TIMEOUT; ii++) {
+               udelay(1);
+               if (BYTE_REG_BITS_IS_ON(MIISR_MIDLE, &regs->MIISR))
+                       break;
+       }
 
-               enable_flow_control_ability(vptr);
-               mac_hw_mibs_init(regs);
-               mac_write_int_mask(vptr->int_mask, regs);
-               mac_clear_isr(regs);
+       writeb(MIICR_MAUTO, &regs->MIICR);
 
+       for (ii = 0; ii < W_MAX_TIMEOUT; ii++) {
+               udelay(1);
+               if (!BYTE_REG_BITS_IS_ON(MIISR_MIDLE, &regs->MIISR))
+                       break;
        }
+
 }
 
 /**
- *     velocity_soft_reset     -       soft reset
- *     @vptr: velocity to reset
+ *     velocity_mii_read       -       read MII data
+ *     @regs: velocity registers
+ *     @index: MII register index
+ *     @data: buffer for received data
  *
- *     Kick off a soft reset of the velocity adapter and then poll
- *     until the reset sequence has completed before returning.
+ *     Perform a single read of an MII 16bit register. Returns zero
+ *     on success or -ETIMEDOUT if the PHY did not respond.
  */
-
-static int velocity_soft_reset(struct velocity_info *vptr)
+static int velocity_mii_read(struct mac_regs __iomem *regs, u8 index, u16 *data)
 {
-       struct mac_regs __iomem * regs = vptr->mac_regs;
-       int i = 0;
+       u16 ww;
 
-       writel(CR0_SFRST, &regs->CR0Set);
+       /*
+        *      Disable MIICR_MAUTO, so that mii addr can be set normally
+        */
+       safe_disable_mii_autopoll(regs);
 
-       for (i = 0; i < W_MAX_TIMEOUT; i++) {
-               udelay(5);
-               if (!DWORD_REG_BITS_IS_ON(CR0_SFRST, &regs->CR0Set))
+       writeb(index, &regs->MIIADR);
+
+       BYTE_REG_BITS_ON(MIICR_RCMD, &regs->MIICR);
+
+       for (ww = 0; ww < W_MAX_TIMEOUT; ww++) {
+               if (!(readb(&regs->MIICR) & MIICR_RCMD))
                        break;
        }
 
-       if (i == W_MAX_TIMEOUT) {
-               writel(CR0_FORSRST, &regs->CR0Set);
-               /* FIXME: PCI POSTING */
-               /* delay 2ms */
-               mdelay(2);
-       }
+       *data = readw(&regs->MIIDATA);
+
+       enable_mii_autopoll(regs);
+       if (ww == W_MAX_TIMEOUT)
+               return -ETIMEDOUT;
        return 0;
 }
 
-static const struct net_device_ops velocity_netdev_ops = {
-       .ndo_open               = velocity_open,
-       .ndo_stop               = velocity_close,
-       .ndo_start_xmit         = velocity_xmit,
-       .ndo_get_stats          = velocity_get_stats,
-       .ndo_validate_addr      = eth_validate_addr,
-       .ndo_set_mac_address    = eth_mac_addr,
-       .ndo_set_multicast_list = velocity_set_multi,
-       .ndo_change_mtu         = velocity_change_mtu,
-       .ndo_do_ioctl           = velocity_ioctl,
-       .ndo_vlan_rx_add_vid    = velocity_vlan_rx_add_vid,
-       .ndo_vlan_rx_kill_vid   = velocity_vlan_rx_kill_vid,
-       .ndo_vlan_rx_register   = velocity_vlan_rx_register,
-};
 
 /**
- *     velocity_found1         -       set up discovered velocity card
- *     @pdev: PCI device
- *     @ent: PCI device table entry that matched
+ *     mii_check_media_mode    -       check media state
+ *     @regs: velocity registers
  *
- *     Configure a discovered adapter from scratch. Return a negative
- *     errno error code on failure paths.
+ *     Check the current MII status and determine the link status
+ *     accordingly
  */
-
-static int __devinit velocity_found1(struct pci_dev *pdev, const struct pci_device_id *ent)
+static u32 mii_check_media_mode(struct mac_regs __iomem *regs)
 {
-       static int first = 1;
-       struct net_device *dev;
-       int i;
-       const char *drv_string;
-       const struct velocity_info_tbl *info = &chip_info_table[ent->driver_data];
-       struct velocity_info *vptr;
-       struct mac_regs __iomem * regs;
-       int ret = -ENOMEM;
+       u32 status = 0;
+       u16 ANAR;
 
-       /* FIXME: this driver, like almost all other ethernet drivers,
-        * can support more than MAX_UNITS.
-        */
-       if (velocity_nics >= MAX_UNITS) {
-               dev_notice(&pdev->dev, "already found %d NICs.\n",
-                          velocity_nics);
-               return -ENODEV;
-       }
+       if (!MII_REG_BITS_IS_ON(BMSR_LNK, MII_REG_BMSR, regs))
+               status |= VELOCITY_LINK_FAIL;
 
-       dev = alloc_etherdev(sizeof(struct velocity_info));
-       if (!dev) {
-               dev_err(&pdev->dev, "allocate net device failed.\n");
-               goto out;
+       if (MII_REG_BITS_IS_ON(G1000CR_1000FD, MII_REG_G1000CR, regs))
+               status |= VELOCITY_SPEED_1000 | VELOCITY_DUPLEX_FULL;
+       else if (MII_REG_BITS_IS_ON(G1000CR_1000, MII_REG_G1000CR, regs))
+               status |= (VELOCITY_SPEED_1000);
+       else {
+               velocity_mii_read(regs, MII_REG_ANAR, &ANAR);
+               if (ANAR & ANAR_TXFD)
+                       status |= (VELOCITY_SPEED_100 | VELOCITY_DUPLEX_FULL);
+               else if (ANAR & ANAR_TX)
+                       status |= VELOCITY_SPEED_100;
+               else if (ANAR & ANAR_10FD)
+                       status |= (VELOCITY_SPEED_10 | VELOCITY_DUPLEX_FULL);
+               else
+                       status |= (VELOCITY_SPEED_10);
        }
 
-       /* Chain it all together */
-
-       SET_NETDEV_DEV(dev, &pdev->dev);
-       vptr = netdev_priv(dev);
-
-
-       if (first) {
-               printk(KERN_INFO "%s Ver. %s\n",
-                       VELOCITY_FULL_DRV_NAM, VELOCITY_VERSION);
-               printk(KERN_INFO "Copyright (c) 2002, 2003 VIA Networking Technologies, Inc.\n");
-               printk(KERN_INFO "Copyright (c) 2004 Red Hat Inc.\n");
-               first = 0;
+       if (MII_REG_BITS_IS_ON(BMCR_AUTO, MII_REG_BMCR, regs)) {
+               velocity_mii_read(regs, MII_REG_ANAR, &ANAR);
+               if ((ANAR & (ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10))
+                   == (ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10)) {
+                       if (MII_REG_BITS_IS_ON(G1000CR_1000 | G1000CR_1000FD, MII_REG_G1000CR, regs))
+                               status |= VELOCITY_AUTONEG_ENABLE;
+               }
        }
 
-       velocity_init_info(pdev, vptr, info);
-
-       vptr->dev = dev;
+       return status;
+}
 
-       dev->irq = pdev->irq;
+/**
+ *     velocity_mii_write      -       write MII data
+ *     @regs: velocity registers
+ *     @index: MII register index
+ *     @data: 16bit data for the MII register
+ *
+ *     Perform a single write to an MII 16bit register. Returns zero
+ *     on success or -ETIMEDOUT if the PHY did not respond.
+ */
+static int velocity_mii_write(struct mac_regs __iomem *regs, u8 mii_addr, u16 data)
+{
+       u16 ww;
 
-       ret = pci_enable_device(pdev);
-       if (ret < 0)
-               goto err_free_dev;
+       /*
+        *      Disable MIICR_MAUTO, so that mii addr can be set normally
+        */
+       safe_disable_mii_autopoll(regs);
 
-       ret = velocity_get_pci_info(vptr, pdev);
-       if (ret < 0) {
-               /* error message already printed */
-               goto err_disable;
-       }
+       /* MII reg offset */
+       writeb(mii_addr, &regs->MIIADR);
+       /* set MII data */
+       writew(data, &regs->MIIDATA);
 
-       ret = pci_request_regions(pdev, VELOCITY_NAME);
-       if (ret < 0) {
-               dev_err(&pdev->dev, "No PCI resources.\n");
-               goto err_disable;
-       }
+       /* turn on MIICR_WCMD */
+       BYTE_REG_BITS_ON(MIICR_WCMD, &regs->MIICR);
 
-       regs = ioremap(vptr->memaddr, VELOCITY_IO_SIZE);
-       if (regs == NULL) {
-               ret = -EIO;
-               goto err_release_res;
+       /* W_MAX_TIMEOUT is the timeout period */
+       for (ww = 0; ww < W_MAX_TIMEOUT; ww++) {
+               udelay(5);
+               if (!(readb(&regs->MIICR) & MIICR_WCMD))
+                       break;
        }
+       enable_mii_autopoll(regs);
 
-       vptr->mac_regs = regs;
+       if (ww == W_MAX_TIMEOUT)
+               return -ETIMEDOUT;
+       return 0;
+}
 
-       mac_wol_reset(regs);
+/**
+ *     set_mii_flow_control    -       flow control setup
+ *     @vptr: velocity interface
+ *
+ *     Set up the flow control on this interface according to
+ *     the supplied user/eeprom options.
+ */
+static void set_mii_flow_control(struct velocity_info *vptr)
+{
+       /*Enable or Disable PAUSE in ANAR */
+       switch (vptr->options.flow_cntl) {
+       case FLOW_CNTL_TX:
+               MII_REG_BITS_OFF(ANAR_PAUSE, MII_REG_ANAR, vptr->mac_regs);
+               MII_REG_BITS_ON(ANAR_ASMDIR, MII_REG_ANAR, vptr->mac_regs);
+               break;
 
-       dev->base_addr = vptr->ioaddr;
+       case FLOW_CNTL_RX:
+               MII_REG_BITS_ON(ANAR_PAUSE, MII_REG_ANAR, vptr->mac_regs);
+               MII_REG_BITS_ON(ANAR_ASMDIR, MII_REG_ANAR, vptr->mac_regs);
+               break;
 
-       for (i = 0; i < 6; i++)
-               dev->dev_addr[i] = readb(&regs->PAR[i]);
+       case FLOW_CNTL_TX_RX:
+               MII_REG_BITS_ON(ANAR_PAUSE, MII_REG_ANAR, vptr->mac_regs);
+               MII_REG_BITS_ON(ANAR_ASMDIR, MII_REG_ANAR, vptr->mac_regs);
+               break;
 
+       case FLOW_CNTL_DISABLE:
+               MII_REG_BITS_OFF(ANAR_PAUSE, MII_REG_ANAR, vptr->mac_regs);
+               MII_REG_BITS_OFF(ANAR_ASMDIR, MII_REG_ANAR, vptr->mac_regs);
+               break;
+       default:
+               break;
+       }
+}
 
-       drv_string = dev_driver_string(&pdev->dev);
+/**
+ *     mii_set_auto_on         -       autonegotiate on
+ *     @vptr: velocity
+ *
+ *     Enable autonegotation on this interface
+ */
+static void mii_set_auto_on(struct velocity_info *vptr)
+{
+       if (MII_REG_BITS_IS_ON(BMCR_AUTO, MII_REG_BMCR, vptr->mac_regs))
+               MII_REG_BITS_ON(BMCR_REAUTO, MII_REG_BMCR, vptr->mac_regs);
+       else
+               MII_REG_BITS_ON(BMCR_AUTO, MII_REG_BMCR, vptr->mac_regs);
+}
 
-       velocity_get_options(&vptr->options, velocity_nics, drv_string);
+static u32 check_connection_type(struct mac_regs __iomem *regs)
+{
+       u32 status = 0;
+       u8 PHYSR0;
+       u16 ANAR;
+       PHYSR0 = readb(&regs->PHYSR0);
 
        /*
-        *      Mask out the options cannot be set to the chip
+          if (!(PHYSR0 & PHYSR0_LINKGD))
+          status|=VELOCITY_LINK_FAIL;
         */
 
-       vptr->options.flags &= info->flags;
+       if (PHYSR0 & PHYSR0_FDPX)
+               status |= VELOCITY_DUPLEX_FULL;
 
-       /*
-        *      Enable the chip specified capbilities
-        */
+       if (PHYSR0 & PHYSR0_SPDG)
+               status |= VELOCITY_SPEED_1000;
+       else if (PHYSR0 & PHYSR0_SPD10)
+               status |= VELOCITY_SPEED_10;
+       else
+               status |= VELOCITY_SPEED_100;
 
-       vptr->flags = vptr->options.flags | (info->flags & 0xFF000000UL);
+       if (MII_REG_BITS_IS_ON(BMCR_AUTO, MII_REG_BMCR, regs)) {
+               velocity_mii_read(regs, MII_REG_ANAR, &ANAR);
+               if ((ANAR & (ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10))
+                   == (ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10)) {
+                       if (MII_REG_BITS_IS_ON(G1000CR_1000 | G1000CR_1000FD, MII_REG_G1000CR, regs))
+                               status |= VELOCITY_AUTONEG_ENABLE;
+               }
+       }
 
-       vptr->wol_opts = vptr->options.wol_opts;
-       vptr->flags |= VELOCITY_FLAGS_WOL_ENABLED;
+       return status;
+}
 
-       vptr->phy_id = MII_GET_PHY_ID(vptr->mac_regs);
 
-       dev->irq = pdev->irq;
-       dev->netdev_ops = &velocity_netdev_ops;
-       dev->ethtool_ops = &velocity_ethtool_ops;
 
-#ifdef  VELOCITY_ZERO_COPY_SUPPORT
-       dev->features |= NETIF_F_SG;
-#endif
-       dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_FILTER |
-               NETIF_F_HW_VLAN_RX;
+/**
+ *     velocity_set_media_mode         -       set media mode
+ *     @mii_status: old MII link state
+ *
+ *     Check the media link state and configure the flow control
+ *     PHY and also velocity hardware setup accordingly. In particular
+ *     we need to set up CD polling and frame bursting.
+ */
+static int velocity_set_media_mode(struct velocity_info *vptr, u32 mii_status)
+{
+       u32 curr_status;
+       struct mac_regs __iomem *regs = vptr->mac_regs;
 
-       if (vptr->flags & VELOCITY_FLAGS_TX_CSUM)
-               dev->features |= NETIF_F_IP_CSUM;
+       vptr->mii_status = mii_check_media_mode(vptr->mac_regs);
+       curr_status = vptr->mii_status & (~VELOCITY_LINK_FAIL);
 
-       ret = register_netdev(dev);
-       if (ret < 0)
-               goto err_iounmap;
+       /* Set mii link status */
+       set_mii_flow_control(vptr);
 
-       if (!velocity_get_link(dev)) {
-               netif_carrier_off(dev);
-               vptr->mii_status |= VELOCITY_LINK_FAIL;
-       }
+       /*
+          Check if new status is consisent with current status
+          if (((mii_status & curr_status) & VELOCITY_AUTONEG_ENABLE)
+          || (mii_status==curr_status)) {
+          vptr->mii_status=mii_check_media_mode(vptr->mac_regs);
+          vptr->mii_status=check_connection_type(vptr->mac_regs);
+          VELOCITY_PRT(MSG_LEVEL_INFO, "Velocity link no change\n");
+          return 0;
+          }
+        */
 
-       velocity_print_info(vptr);
-       pci_set_drvdata(pdev, dev);
+       if (PHYID_GET_PHY_ID(vptr->phy_id) == PHYID_CICADA_CS8201)
+               MII_REG_BITS_ON(AUXCR_MDPPS, MII_REG_AUXCR, vptr->mac_regs);
 
-       /* and leave the chip powered down */
+       /*
+        *      If connection type is AUTO
+        */
+       if (mii_status & VELOCITY_AUTONEG_ENABLE) {
+               VELOCITY_PRT(MSG_LEVEL_INFO, "Velocity is AUTO mode\n");
+               /* clear force MAC mode bit */
+               BYTE_REG_BITS_OFF(CHIPGCR_FCMODE, &regs->CHIPGCR);
+               /* set duplex mode of MAC according to duplex mode of MII */
+               MII_REG_BITS_ON(ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10, MII_REG_ANAR, vptr->mac_regs);
+               MII_REG_BITS_ON(G1000CR_1000FD | G1000CR_1000, MII_REG_G1000CR, vptr->mac_regs);
+               MII_REG_BITS_ON(BMCR_SPEED1G, MII_REG_BMCR, vptr->mac_regs);
 
-       pci_set_power_state(pdev, PCI_D3hot);
-#ifdef CONFIG_PM
-       {
-               unsigned long flags;
+               /* enable AUTO-NEGO mode */
+               mii_set_auto_on(vptr);
+       } else {
+               u16 ANAR;
+               u8 CHIPGCR;
 
-               spin_lock_irqsave(&velocity_dev_list_lock, flags);
-               list_add(&vptr->list, &velocity_dev_list);
-               spin_unlock_irqrestore(&velocity_dev_list_lock, flags);
-       }
-#endif
-       velocity_nics++;
-out:
-       return ret;
+               /*
+                * 1. if it's 3119, disable frame bursting in halfduplex mode
+                *    and enable it in fullduplex mode
+                * 2. set correct MII/GMII and half/full duplex mode in CHIPGCR
+                * 3. only enable CD heart beat counter in 10HD mode
+                */
 
-err_iounmap:
-       iounmap(regs);
-err_release_res:
-       pci_release_regions(pdev);
-err_disable:
-       pci_disable_device(pdev);
-err_free_dev:
-       free_netdev(dev);
-       goto out;
-}
+               /* set force MAC mode bit */
+               BYTE_REG_BITS_ON(CHIPGCR_FCMODE, &regs->CHIPGCR);
 
-/**
- *     velocity_print_info     -       per driver data
- *     @vptr: velocity
- *
- *     Print per driver data as the kernel driver finds Velocity
- *     hardware
- */
+               CHIPGCR = readb(&regs->CHIPGCR);
+               CHIPGCR &= ~CHIPGCR_FCGMII;
 
-static void __devinit velocity_print_info(struct velocity_info *vptr)
-{
-       struct net_device *dev = vptr->dev;
+               if (mii_status & VELOCITY_DUPLEX_FULL) {
+                       CHIPGCR |= CHIPGCR_FCFDX;
+                       writeb(CHIPGCR, &regs->CHIPGCR);
+                       VELOCITY_PRT(MSG_LEVEL_INFO, "set Velocity to forced full mode\n");
+                       if (vptr->rev_id < REV_ID_VT3216_A0)
+                               BYTE_REG_BITS_OFF(TCR_TB2BDIS, &regs->TCR);
+               } else {
+                       CHIPGCR &= ~CHIPGCR_FCFDX;
+                       VELOCITY_PRT(MSG_LEVEL_INFO, "set Velocity to forced half mode\n");
+                       writeb(CHIPGCR, &regs->CHIPGCR);
+                       if (vptr->rev_id < REV_ID_VT3216_A0)
+                               BYTE_REG_BITS_ON(TCR_TB2BDIS, &regs->TCR);
+               }
 
-       printk(KERN_INFO "%s: %s\n", dev->name, get_chip_name(vptr->chip_id));
-       printk(KERN_INFO "%s: Ethernet Address: %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X\n",
-               dev->name,
-               dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
-               dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
+               MII_REG_BITS_OFF(G1000CR_1000FD | G1000CR_1000, MII_REG_G1000CR, vptr->mac_regs);
+
+               if (!(mii_status & VELOCITY_DUPLEX_FULL) && (mii_status & VELOCITY_SPEED_10))
+                       BYTE_REG_BITS_OFF(TESTCFG_HBDIS, &regs->TESTCFG);
+               else
+                       BYTE_REG_BITS_ON(TESTCFG_HBDIS, &regs->TESTCFG);
+
+               /* MII_REG_BITS_OFF(BMCR_SPEED1G, MII_REG_BMCR, vptr->mac_regs); */
+               velocity_mii_read(vptr->mac_regs, MII_REG_ANAR, &ANAR);
+               ANAR &= (~(ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10));
+               if (mii_status & VELOCITY_SPEED_100) {
+                       if (mii_status & VELOCITY_DUPLEX_FULL)
+                               ANAR |= ANAR_TXFD;
+                       else
+                               ANAR |= ANAR_TX;
+               } else {
+                       if (mii_status & VELOCITY_DUPLEX_FULL)
+                               ANAR |= ANAR_10FD;
+                       else
+                               ANAR |= ANAR_10;
+               }
+               velocity_mii_write(vptr->mac_regs, MII_REG_ANAR, ANAR);
+               /* enable AUTO-NEGO mode */
+               mii_set_auto_on(vptr);
+               /* MII_REG_BITS_ON(BMCR_AUTO, MII_REG_BMCR, vptr->mac_regs); */
+       }
+       /* vptr->mii_status=mii_check_media_mode(vptr->mac_regs); */
+       /* vptr->mii_status=check_connection_type(vptr->mac_regs); */
+       return VELOCITY_LINK_CHANGE;
 }
 
 /**
- *     velocity_init_info      -       init private data
- *     @pdev: PCI device
- *     @vptr: Velocity info
- *     @info: Board type
+ *     velocity_print_link_status      -       link status reporting
+ *     @vptr: velocity to report on
  *
- *     Set up the initial velocity_info struct for the device that has been
- *     discovered.
+ *     Turn the link status of the velocity card into a kernel log
+ *     description of the new link state, detailing speed and duplex
+ *     status
  */
-
-static void __devinit velocity_init_info(struct pci_dev *pdev,
-                                        struct velocity_info *vptr,
-                                        const struct velocity_info_tbl *info)
+static void velocity_print_link_status(struct velocity_info *vptr)
 {
-       memset(vptr, 0, sizeof(struct velocity_info));
 
-       vptr->pdev = pdev;
-       vptr->chip_id = info->chip_id;
-       vptr->tx.numq = info->txqueue;
-       vptr->multicast_limit = MCAM_SIZE;
-       spin_lock_init(&vptr->lock);
-       INIT_LIST_HEAD(&vptr->list);
+       if (vptr->mii_status & VELOCITY_LINK_FAIL) {
+               VELOCITY_PRT(MSG_LEVEL_INFO, KERN_NOTICE "%s: failed to detect cable link\n", vptr->dev->name);
+       } else if (vptr->options.spd_dpx == SPD_DPX_AUTO) {
+               VELOCITY_PRT(MSG_LEVEL_INFO, KERN_NOTICE "%s: Link auto-negotiation", vptr->dev->name);
+
+               if (vptr->mii_status & VELOCITY_SPEED_1000)
+                       VELOCITY_PRT(MSG_LEVEL_INFO, " speed 1000M bps");
+               else if (vptr->mii_status & VELOCITY_SPEED_100)
+                       VELOCITY_PRT(MSG_LEVEL_INFO, " speed 100M bps");
+               else
+                       VELOCITY_PRT(MSG_LEVEL_INFO, " speed 10M bps");
+
+               if (vptr->mii_status & VELOCITY_DUPLEX_FULL)
+                       VELOCITY_PRT(MSG_LEVEL_INFO, " full duplex\n");
+               else
+                       VELOCITY_PRT(MSG_LEVEL_INFO, " half duplex\n");
+       } else {
+               VELOCITY_PRT(MSG_LEVEL_INFO, KERN_NOTICE "%s: Link forced", vptr->dev->name);
+               switch (vptr->options.spd_dpx) {
+               case SPD_DPX_100_HALF:
+                       VELOCITY_PRT(MSG_LEVEL_INFO, " speed 100M bps half duplex\n");
+                       break;
+               case SPD_DPX_100_FULL:
+                       VELOCITY_PRT(MSG_LEVEL_INFO, " speed 100M bps full duplex\n");
+                       break;
+               case SPD_DPX_10_HALF:
+                       VELOCITY_PRT(MSG_LEVEL_INFO, " speed 10M bps half duplex\n");
+                       break;
+               case SPD_DPX_10_FULL:
+                       VELOCITY_PRT(MSG_LEVEL_INFO, " speed 10M bps full duplex\n");
+                       break;
+               default:
+                       break;
+               }
+       }
 }
 
 /**
- *     velocity_get_pci_info   -       retrieve PCI info for device
- *     @vptr: velocity device
- *     @pdev: PCI device it matches
+ *     enable_flow_control_ability     -       flow control
+ *     @vptr: veloity to configure
  *
- *     Retrieve the PCI configuration space data that interests us from
- *     the kernel PCI layer
+ *     Set up flow control according to the flow control options
+ *     determined by the eeprom/configuration.
  */
-
-static int __devinit velocity_get_pci_info(struct velocity_info *vptr, struct pci_dev *pdev)
+static void enable_flow_control_ability(struct velocity_info *vptr)
 {
-       vptr->rev_id = pdev->revision;
 
-       pci_set_master(pdev);
+       struct mac_regs __iomem *regs = vptr->mac_regs;
 
-       vptr->ioaddr = pci_resource_start(pdev, 0);
-       vptr->memaddr = pci_resource_start(pdev, 1);
+       switch (vptr->options.flow_cntl) {
 
-       if (!(pci_resource_flags(pdev, 0) & IORESOURCE_IO)) {
-               dev_err(&pdev->dev,
-                          "region #0 is not an I/O resource, aborting.\n");
-               return -EINVAL;
-       }
+       case FLOW_CNTL_DEFAULT:
+               if (BYTE_REG_BITS_IS_ON(PHYSR0_RXFLC, &regs->PHYSR0))
+                       writel(CR0_FDXRFCEN, &regs->CR0Set);
+               else
+                       writel(CR0_FDXRFCEN, &regs->CR0Clr);
 
-       if ((pci_resource_flags(pdev, 1) & IORESOURCE_IO)) {
-               dev_err(&pdev->dev,
-                          "region #1 is an I/O resource, aborting.\n");
-               return -EINVAL;
-       }
+               if (BYTE_REG_BITS_IS_ON(PHYSR0_TXFLC, &regs->PHYSR0))
+                       writel(CR0_FDXTFCEN, &regs->CR0Set);
+               else
+                       writel(CR0_FDXTFCEN, &regs->CR0Clr);
+               break;
 
-       if (pci_resource_len(pdev, 1) < VELOCITY_IO_SIZE) {
-               dev_err(&pdev->dev, "region #1 is too small.\n");
-               return -EINVAL;
+       case FLOW_CNTL_TX:
+               writel(CR0_FDXTFCEN, &regs->CR0Set);
+               writel(CR0_FDXRFCEN, &regs->CR0Clr);
+               break;
+
+       case FLOW_CNTL_RX:
+               writel(CR0_FDXRFCEN, &regs->CR0Set);
+               writel(CR0_FDXTFCEN, &regs->CR0Clr);
+               break;
+
+       case FLOW_CNTL_TX_RX:
+               writel(CR0_FDXTFCEN, &regs->CR0Set);
+               writel(CR0_FDXRFCEN, &regs->CR0Set);
+               break;
+
+       case FLOW_CNTL_DISABLE:
+               writel(CR0_FDXRFCEN, &regs->CR0Clr);
+               writel(CR0_FDXTFCEN, &regs->CR0Clr);
+               break;
+
+       default:
+               break;
        }
-       vptr->pdev = pdev;
 
-       return 0;
 }
 
 /**
- *     velocity_init_dma_rings -       set up DMA rings
- *     @vptr: Velocity to set up
+ *     velocity_soft_reset     -       soft reset
+ *     @vptr: velocity to reset
  *
- *     Allocate PCI mapped DMA rings for the receive and transmit layer
- *     to use.
+ *     Kick off a soft reset of the velocity adapter and then poll
+ *     until the reset sequence has completed before returning.
  */
-
-static int velocity_init_dma_rings(struct velocity_info *vptr)
+static int velocity_soft_reset(struct velocity_info *vptr)
 {
-       struct velocity_opt *opt = &vptr->options;
-       const unsigned int rx_ring_size = opt->numrx * sizeof(struct rx_desc);
-       const unsigned int tx_ring_size = opt->numtx * sizeof(struct tx_desc);
-       struct pci_dev *pdev = vptr->pdev;
-       dma_addr_t pool_dma;
-       void *pool;
-       unsigned int i;
-
-       /*
-        * Allocate all RD/TD rings a single pool.
-        *
-        * pci_alloc_consistent() fulfills the requirement for 64 bytes
-        * alignment
-        */
-       pool = pci_alloc_consistent(pdev, tx_ring_size * vptr->tx.numq +
-                                   rx_ring_size, &pool_dma);
-       if (!pool) {
-               dev_err(&pdev->dev, "%s : DMA memory allocation failed.\n",
-                       vptr->dev->name);
-               return -ENOMEM;
-       }
-
-       vptr->rx.ring = pool;
-       vptr->rx.pool_dma = pool_dma;
+       struct mac_regs __iomem *regs = vptr->mac_regs;
+       int i = 0;
 
-       pool += rx_ring_size;
-       pool_dma += rx_ring_size;
+       writel(CR0_SFRST, &regs->CR0Set);
 
-       for (i = 0; i < vptr->tx.numq; i++) {
-               vptr->tx.rings[i] = pool;
-               vptr->tx.pool_dma[i] = pool_dma;
-               pool += tx_ring_size;
-               pool_dma += tx_ring_size;
+       for (i = 0; i < W_MAX_TIMEOUT; i++) {
+               udelay(5);
+               if (!DWORD_REG_BITS_IS_ON(CR0_SFRST, &regs->CR0Set))
+                       break;
        }
 
+       if (i == W_MAX_TIMEOUT) {
+               writel(CR0_FORSRST, &regs->CR0Set);
+               /* FIXME: PCI POSTING */
+               /* delay 2ms */
+               mdelay(2);
+       }
        return 0;
 }
 
 /**
- *     velocity_free_dma_rings -       free PCI ring pointers
- *     @vptr: Velocity to free from
+ *     velocity_set_multi      -       filter list change callback
+ *     @dev: network device
  *
- *     Clean up the PCI ring buffers allocated to this velocity.
+ *     Called by the network layer when the filter lists need to change
+ *     for a velocity adapter. Reload the CAMs with the new address
+ *     filter ruleset.
  */
-
-static void velocity_free_dma_rings(struct velocity_info *vptr)
-{
-       const int size = vptr->options.numrx * sizeof(struct rx_desc) +
-               vptr->options.numtx * sizeof(struct tx_desc) * vptr->tx.numq;
-
-       pci_free_consistent(vptr->pdev, size, vptr->rx.ring, vptr->rx.pool_dma);
-}
-
-static void velocity_give_many_rx_descs(struct velocity_info *vptr)
+static void velocity_set_multi(struct net_device *dev)
 {
+       struct velocity_info *vptr = netdev_priv(dev);
        struct mac_regs __iomem *regs = vptr->mac_regs;
-       int avail, dirty, unusable;
-
-       /*
-        * RD number must be equal to 4X per hardware spec
-        * (programming guide rev 1.20, p.13)
-        */
-       if (vptr->rx.filled < 4)
-               return;
-
-       wmb();
-
-       unusable = vptr->rx.filled & 0x0003;
-       dirty = vptr->rx.dirty - unusable;
-       for (avail = vptr->rx.filled & 0xfffc; avail; avail--) {
-               dirty = (dirty > 0) ? dirty - 1 : vptr->options.numrx - 1;
-               vptr->rx.ring[dirty].rdesc0.len |= OWNED_BY_NIC;
-       }
-
-       writew(vptr->rx.filled & 0xfffc, &regs->RBRDU);
-       vptr->rx.filled = unusable;
-}
-
-static int velocity_rx_refill(struct velocity_info *vptr)
-{
-       int dirty = vptr->rx.dirty, done = 0;
-
-       do {
-               struct rx_desc *rd = vptr->rx.ring + dirty;
+       u8 rx_mode;
+       int i;
+       struct dev_mc_list *mclist;
 
-               /* Fine for an all zero Rx desc at init time as well */
-               if (rd->rdesc0.len & OWNED_BY_NIC)
-                       break;
+       if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */
+               writel(0xffffffff, &regs->MARCAM[0]);
+               writel(0xffffffff, &regs->MARCAM[4]);
+               rx_mode = (RCR_AM | RCR_AB | RCR_PROM);
+       } else if ((dev->mc_count > vptr->multicast_limit)
+                  || (dev->flags & IFF_ALLMULTI)) {
+               writel(0xffffffff, &regs->MARCAM[0]);
+               writel(0xffffffff, &regs->MARCAM[4]);
+               rx_mode = (RCR_AM | RCR_AB);
+       } else {
+               int offset = MCAM_SIZE - vptr->multicast_limit;
+               mac_get_cam_mask(regs, vptr->mCAMmask);
 
-               if (!vptr->rx.info[dirty].skb) {
-                       if (velocity_alloc_rx_buf(vptr, dirty) < 0)
-                               break;
+               for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; i++, mclist = mclist->next) {
+                       mac_set_cam(regs, i + offset, mclist->dmi_addr);
+                       vptr->mCAMmask[(offset + i) / 8] |= 1 << ((offset + i) & 7);
                }
-               done++;
-               dirty = (dirty < vptr->options.numrx - 1) ? dirty + 1 : 0;
-       } while (dirty != vptr->rx.curr);
 
-       if (done) {
-               vptr->rx.dirty = dirty;
-               vptr->rx.filled += done;
+               mac_set_cam_mask(regs, vptr->mCAMmask);
+               rx_mode = RCR_AM | RCR_AB | RCR_AP;
        }
+       if (dev->mtu > 1500)
+               rx_mode |= RCR_AL;
 
-       return done;
-}
+       BYTE_REG_BITS_ON(rx_mode, &regs->RCR);
 
-static void velocity_set_rxbufsize(struct velocity_info *vptr, int mtu)
-{
-       vptr->rx.buf_sz = (mtu <= ETH_DATA_LEN) ? PKT_BUF_SZ : mtu + 32;
 }
 
+/*
+ * MII access , media link mode setting functions
+ */
+
 /**
- *     velocity_init_rd_ring   -       set up receive ring
- *     @vptr: velocity to configure
+ *     mii_init        -       set up MII
+ *     @vptr: velocity adapter
+ *     @mii_status:  links tatus
  *
- *     Allocate and set up the receive buffers for each ring slot and
- *     assign them to the network adapter.
+ *     Set up the PHY for the current link state.
  */
-
-static int velocity_init_rd_ring(struct velocity_info *vptr)
+static void mii_init(struct velocity_info *vptr, u32 mii_status)
 {
-       int ret = -ENOMEM;
-
-       vptr->rx.info = kcalloc(vptr->options.numrx,
-                               sizeof(struct velocity_rd_info), GFP_KERNEL);
-       if (!vptr->rx.info)
-               goto out;
+       u16 BMCR;
 
-       velocity_init_rx_ring_indexes(vptr);
+       switch (PHYID_GET_PHY_ID(vptr->phy_id)) {
+       case PHYID_CICADA_CS8201:
+               /*
+                *      Reset to hardware default
+                */
+               MII_REG_BITS_OFF((ANAR_ASMDIR | ANAR_PAUSE), MII_REG_ANAR, vptr->mac_regs);
+               /*
+                *      Turn on ECHODIS bit in NWay-forced full mode and turn it
+                *      off it in NWay-forced half mode for NWay-forced v.s.
+                *      legacy-forced issue.
+                */
+               if (vptr->mii_status & VELOCITY_DUPLEX_FULL)
+                       MII_REG_BITS_ON(TCSR_ECHODIS, MII_REG_TCSR, vptr->mac_regs);
+               else
+                       MII_REG_BITS_OFF(TCSR_ECHODIS, MII_REG_TCSR, vptr->mac_regs);
+               /*
+                *      Turn on Link/Activity LED enable bit for CIS8201
+                */
+               MII_REG_BITS_ON(PLED_LALBE, MII_REG_PLED, vptr->mac_regs);
+               break;
+       case PHYID_VT3216_32BIT:
+       case PHYID_VT3216_64BIT:
+               /*
+                *      Reset to hardware default
+                */
+               MII_REG_BITS_ON((ANAR_ASMDIR | ANAR_PAUSE), MII_REG_ANAR, vptr->mac_regs);
+               /*
+                *      Turn on ECHODIS bit in NWay-forced full mode and turn it
+                *      off it in NWay-forced half mode for NWay-forced v.s.
+                *      legacy-forced issue
+                */
+               if (vptr->mii_status & VELOCITY_DUPLEX_FULL)
+                       MII_REG_BITS_ON(TCSR_ECHODIS, MII_REG_TCSR, vptr->mac_regs);
+               else
+                       MII_REG_BITS_OFF(TCSR_ECHODIS, MII_REG_TCSR, vptr->mac_regs);
+               break;
 
-       if (velocity_rx_refill(vptr) != vptr->options.numrx) {
-               VELOCITY_PRT(MSG_LEVEL_ERR, KERN_ERR
-                       "%s: failed to allocate RX buffer.\n", vptr->dev->name);
-               velocity_free_rd_ring(vptr);
-               goto out;
+       case PHYID_MARVELL_1000:
+       case PHYID_MARVELL_1000S:
+               /*
+                *      Assert CRS on Transmit
+                */
+               MII_REG_BITS_ON(PSCR_ACRSTX, MII_REG_PSCR, vptr->mac_regs);
+               /*
+                *      Reset to hardware default
+                */
+               MII_REG_BITS_ON((ANAR_ASMDIR | ANAR_PAUSE), MII_REG_ANAR, vptr->mac_regs);
+               break;
+       default:
+               ;
+       }
+       velocity_mii_read(vptr->mac_regs, MII_REG_BMCR, &BMCR);
+       if (BMCR & BMCR_ISO) {
+               BMCR &= ~BMCR_ISO;
+               velocity_mii_write(vptr->mac_regs, MII_REG_BMCR, BMCR);
        }
-
-       ret = 0;
-out:
-       return ret;
 }
 
+
 /**
- *     velocity_free_rd_ring   -       free receive ring
- *     @vptr: velocity to clean up
+ *     velocity_init_registers -       initialise MAC registers
+ *     @vptr: velocity to init
+ *     @type: type of initialisation (hot or cold)
  *
- *     Free the receive buffers for each ring slot and any
- *     attached socket buffers that need to go away.
+ *     Initialise the MAC on a reset or on first set up on the
+ *     hardware.
  */
-
-static void velocity_free_rd_ring(struct velocity_info *vptr)
+static void velocity_init_registers(struct velocity_info *vptr,
+                                   enum velocity_init_type type)
 {
-       int i;
-
-       if (vptr->rx.info == NULL)
-               return;
+       struct mac_regs __iomem *regs = vptr->mac_regs;
+       int i, mii_status;
 
-       for (i = 0; i < vptr->options.numrx; i++) {
-               struct velocity_rd_info *rd_info = &(vptr->rx.info[i]);
-               struct rx_desc *rd = vptr->rx.ring + i;
+       mac_wol_reset(regs);
 
-               memset(rd, 0, sizeof(*rd));
+       switch (type) {
+       case VELOCITY_INIT_RESET:
+       case VELOCITY_INIT_WOL:
 
-               if (!rd_info->skb)
-                       continue;
-               pci_unmap_single(vptr->pdev, rd_info->skb_dma, vptr->rx.buf_sz,
-                                PCI_DMA_FROMDEVICE);
-               rd_info->skb_dma = 0;
+               netif_stop_queue(vptr->dev);
 
-               dev_kfree_skb(rd_info->skb);
-               rd_info->skb = NULL;
-       }
+               /*
+                *      Reset RX to prevent RX pointer not on the 4X location
+                */
+               velocity_rx_reset(vptr);
+               mac_rx_queue_run(regs);
+               mac_rx_queue_wake(regs);
 
-       kfree(vptr->rx.info);
-       vptr->rx.info = NULL;
-}
+               mii_status = velocity_get_opt_media_mode(vptr);
+               if (velocity_set_media_mode(vptr, mii_status) != VELOCITY_LINK_CHANGE) {
+                       velocity_print_link_status(vptr);
+                       if (!(vptr->mii_status & VELOCITY_LINK_FAIL))
+                               netif_wake_queue(vptr->dev);
+               }
 
-/**
- *     velocity_init_td_ring   -       set up transmit ring
- *     @vptr:  velocity
- *
- *     Set up the transmit ring and chain the ring pointers together.
- *     Returns zero on success or a negative posix errno code for
- *     failure.
- */
+               enable_flow_control_ability(vptr);
 
-static int velocity_init_td_ring(struct velocity_info *vptr)
-{
-       dma_addr_t curr;
-       int j;
+               mac_clear_isr(regs);
+               writel(CR0_STOP, &regs->CR0Clr);
+               writel((CR0_DPOLL | CR0_TXON | CR0_RXON | CR0_STRT),
+                                                       &regs->CR0Set);
 
-       /* Init the TD ring entries */
-       for (j = 0; j < vptr->tx.numq; j++) {
-               curr = vptr->tx.pool_dma[j];
+               break;
 
-               vptr->tx.infos[j] = kcalloc(vptr->options.numtx,
-                                           sizeof(struct velocity_td_info),
-                                           GFP_KERNEL);
-               if (!vptr->tx.infos[j]) {
-                       while(--j >= 0)
-                               kfree(vptr->tx.infos[j]);
-                       return -ENOMEM;
-               }
+       case VELOCITY_INIT_COLD:
+       default:
+               /*
+                *      Do reset
+                */
+               velocity_soft_reset(vptr);
+               mdelay(5);
 
-               vptr->tx.tail[j] = vptr->tx.curr[j] = vptr->tx.used[j] = 0;
-       }
-       return 0;
-}
+               mac_eeprom_reload(regs);
+               for (i = 0; i < 6; i++)
+                       writeb(vptr->dev->dev_addr[i], &(regs->PAR[i]));
 
-/*
- *     FIXME: could we merge this with velocity_free_tx_buf ?
- */
+               /*
+                *      clear Pre_ACPI bit.
+                */
+               BYTE_REG_BITS_OFF(CFGA_PACPI, &(regs->CFGA));
+               mac_set_rx_thresh(regs, vptr->options.rx_thresh);
+               mac_set_dma_length(regs, vptr->options.DMA_length);
 
-static void velocity_free_td_ring_entry(struct velocity_info *vptr,
-                                                        int q, int n)
-{
-       struct velocity_td_info * td_info = &(vptr->tx.infos[q][n]);
-       int i;
+               writeb(WOLCFG_SAM | WOLCFG_SAB, &regs->WOLCFGSet);
+               /*
+                *      Back off algorithm use original IEEE standard
+                */
+               BYTE_REG_BITS_SET(CFGB_OFSET, (CFGB_CRANDOM | CFGB_CAP | CFGB_MBA | CFGB_BAKOPT), &regs->CFGB);
 
-       if (td_info == NULL)
-               return;
+               /*
+                *      Init CAM filter
+                */
+               velocity_init_cam_filter(vptr);
 
-       if (td_info->skb) {
-               for (i = 0; i < td_info->nskb_dma; i++)
-               {
-                       if (td_info->skb_dma[i]) {
-                               pci_unmap_single(vptr->pdev, td_info->skb_dma[i],
-                                       td_info->skb->len, PCI_DMA_TODEVICE);
-                               td_info->skb_dma[i] = 0;
-                       }
-               }
-               dev_kfree_skb(td_info->skb);
-               td_info->skb = NULL;
-       }
-}
+               /*
+                *      Set packet filter: Receive directed and broadcast address
+                */
+               velocity_set_multi(vptr->dev);
 
-/**
- *     velocity_free_td_ring   -       free td ring
- *     @vptr: velocity
- *
- *     Free up the transmit ring for this particular velocity adapter.
- *     We free the ring contents but not the ring itself.
- */
+               /*
+                *      Enable MII auto-polling
+                */
+               enable_mii_autopoll(regs);
 
-static void velocity_free_td_ring(struct velocity_info *vptr)
-{
-       int i, j;
+               vptr->int_mask = INT_MASK_DEF;
 
-       for (j = 0; j < vptr->tx.numq; j++) {
-               if (vptr->tx.infos[j] == NULL)
-                       continue;
-               for (i = 0; i < vptr->options.numtx; i++) {
-                       velocity_free_td_ring_entry(vptr, j, i);
+               writel(vptr->rx.pool_dma, &regs->RDBaseLo);
+               writew(vptr->options.numrx - 1, &regs->RDCSize);
+               mac_rx_queue_run(regs);
+               mac_rx_queue_wake(regs);
 
-               }
-               kfree(vptr->tx.infos[j]);
-               vptr->tx.infos[j] = NULL;
-       }
-}
+               writew(vptr->options.numtx - 1, &regs->TDCSize);
 
-/**
- *     velocity_rx_srv         -       service RX interrupt
- *     @vptr: velocity
- *     @status: adapter status (unused)
- *
- *     Walk the receive ring of the velocity adapter and remove
- *     any received packets from the receive queue. Hand the ring
- *     slots back to the adapter for reuse.
- */
+               for (i = 0; i < vptr->tx.numq; i++) {
+                       writel(vptr->tx.pool_dma[i], &regs->TDBaseLo[i]);
+                       mac_tx_queue_run(regs, i);
+               }
 
-static int velocity_rx_srv(struct velocity_info *vptr, int status)
-{
-       struct net_device_stats *stats = &vptr->dev->stats;
-       int rd_curr = vptr->rx.curr;
-       int works = 0;
+               init_flow_control_register(vptr);
 
-       do {
-               struct rx_desc *rd = vptr->rx.ring + rd_curr;
+               writel(CR0_STOP, &regs->CR0Clr);
+               writel((CR0_DPOLL | CR0_TXON | CR0_RXON | CR0_STRT), &regs->CR0Set);
 
-               if (!vptr->rx.info[rd_curr].skb)
-                       break;
+               mii_status = velocity_get_opt_media_mode(vptr);
+               netif_stop_queue(vptr->dev);
 
-               if (rd->rdesc0.len & OWNED_BY_NIC)
-                       break;
+               mii_init(vptr, mii_status);
 
-               rmb();
+               if (velocity_set_media_mode(vptr, mii_status) != VELOCITY_LINK_CHANGE) {
+                       velocity_print_link_status(vptr);
+                       if (!(vptr->mii_status & VELOCITY_LINK_FAIL))
+                               netif_wake_queue(vptr->dev);
+               }
 
-               /*
-                *      Don't drop CE or RL error frame although RXOK is off
-                */
-               if (rd->rdesc0.RSR & (RSR_RXOK | RSR_CE | RSR_RL)) {
-                       if (velocity_receive_frame(vptr, rd_curr) < 0)
-                               stats->rx_dropped++;
-               } else {
-                       if (rd->rdesc0.RSR & RSR_CRC)
-                               stats->rx_crc_errors++;
-                       if (rd->rdesc0.RSR & RSR_FAE)
-                               stats->rx_frame_errors++;
+               enable_flow_control_ability(vptr);
+               mac_hw_mibs_init(regs);
+               mac_write_int_mask(vptr->int_mask, regs);
+               mac_clear_isr(regs);
 
-                       stats->rx_dropped++;
-               }
+       }
+}
 
-               rd->size |= RX_INTEN;
+static void velocity_give_many_rx_descs(struct velocity_info *vptr)
+{
+       struct mac_regs __iomem *regs = vptr->mac_regs;
+       int avail, dirty, unusable;
 
-               rd_curr++;
-               if (rd_curr >= vptr->options.numrx)
-                       rd_curr = 0;
-       } while (++works <= 15);
+       /*
+        * RD number must be equal to 4X per hardware spec
+        * (programming guide rev 1.20, p.13)
+        */
+       if (vptr->rx.filled < 4)
+               return;
 
-       vptr->rx.curr = rd_curr;
+       wmb();
 
-       if ((works > 0) && (velocity_rx_refill(vptr) > 0))
-               velocity_give_many_rx_descs(vptr);
+       unusable = vptr->rx.filled & 0x0003;
+       dirty = vptr->rx.dirty - unusable;
+       for (avail = vptr->rx.filled & 0xfffc; avail; avail--) {
+               dirty = (dirty > 0) ? dirty - 1 : vptr->options.numrx - 1;
+               vptr->rx.ring[dirty].rdesc0.len |= OWNED_BY_NIC;
+       }
 
-       VAR_USED(stats);
-       return works;
+       writew(vptr->rx.filled & 0xfffc, &regs->RBRDU);
+       vptr->rx.filled = unusable;
 }
 
 /**
- *     velocity_rx_csum        -       checksum process
- *     @rd: receive packet descriptor
- *     @skb: network layer packet buffer
+ *     velocity_init_dma_rings -       set up DMA rings
+ *     @vptr: Velocity to set up
  *
- *     Process the status bits for the received packet and determine
- *     if the checksum was computed and verified by the hardware
+ *     Allocate PCI mapped DMA rings for the receive and transmit layer
+ *     to use.
  */
-
-static inline void velocity_rx_csum(struct rx_desc *rd, struct sk_buff *skb)
+static int velocity_init_dma_rings(struct velocity_info *vptr)
 {
-       skb->ip_summed = CHECKSUM_NONE;
+       struct velocity_opt *opt = &vptr->options;
+       const unsigned int rx_ring_size = opt->numrx * sizeof(struct rx_desc);
+       const unsigned int tx_ring_size = opt->numtx * sizeof(struct tx_desc);
+       struct pci_dev *pdev = vptr->pdev;
+       dma_addr_t pool_dma;
+       void *pool;
+       unsigned int i;
 
-       if (rd->rdesc1.CSM & CSM_IPKT) {
-               if (rd->rdesc1.CSM & CSM_IPOK) {
-                       if ((rd->rdesc1.CSM & CSM_TCPKT) ||
-                                       (rd->rdesc1.CSM & CSM_UDPKT)) {
-                               if (!(rd->rdesc1.CSM & CSM_TUPOK)) {
-                                       return;
-                               }
-                       }
-                       skb->ip_summed = CHECKSUM_UNNECESSARY;
-               }
+       /*
+        * Allocate all RD/TD rings a single pool.
+        *
+        * pci_alloc_consistent() fulfills the requirement for 64 bytes
+        * alignment
+        */
+       pool = pci_alloc_consistent(pdev, tx_ring_size * vptr->tx.numq +
+                                   rx_ring_size, &pool_dma);
+       if (!pool) {
+               dev_err(&pdev->dev, "%s : DMA memory allocation failed.\n",
+                       vptr->dev->name);
+               return -ENOMEM;
        }
-}
 
-/**
- *     velocity_rx_copy        -       in place Rx copy for small packets
- *     @rx_skb: network layer packet buffer candidate
- *     @pkt_size: received data size
- *     @rd: receive packet descriptor
- *     @dev: network device
- *
- *     Replace the current skb that is scheduled for Rx processing by a
- *     shorter, immediatly allocated skb, if the received packet is small
- *     enough. This function returns a negative value if the received
- *     packet is too big or if memory is exhausted.
- */
-static int velocity_rx_copy(struct sk_buff **rx_skb, int pkt_size,
-                           struct velocity_info *vptr)
-{
-       int ret = -1;
-       if (pkt_size < rx_copybreak) {
-               struct sk_buff *new_skb;
+       vptr->rx.ring = pool;
+       vptr->rx.pool_dma = pool_dma;
 
-               new_skb = netdev_alloc_skb(vptr->dev, pkt_size + 2);
-               if (new_skb) {
-                       new_skb->ip_summed = rx_skb[0]->ip_summed;
-                       skb_reserve(new_skb, 2);
-                       skb_copy_from_linear_data(*rx_skb, new_skb->data, pkt_size);
-                       *rx_skb = new_skb;
-                       ret = 0;
-               }
+       pool += rx_ring_size;
+       pool_dma += rx_ring_size;
 
+       for (i = 0; i < vptr->tx.numq; i++) {
+               vptr->tx.rings[i] = pool;
+               vptr->tx.pool_dma[i] = pool_dma;
+               pool += tx_ring_size;
+               pool_dma += tx_ring_size;
        }
-       return ret;
-}
 
-/**
- *     velocity_iph_realign    -       IP header alignment
- *     @vptr: velocity we are handling
- *     @skb: network layer packet buffer
- *     @pkt_size: received data size
- *
- *     Align IP header on a 2 bytes boundary. This behavior can be
- *     configured by the user.
- */
-static inline void velocity_iph_realign(struct velocity_info *vptr,
-                                       struct sk_buff *skb, int pkt_size)
-{
-       if (vptr->flags & VELOCITY_FLAGS_IP_ALIGN) {
-               memmove(skb->data + 2, skb->data, pkt_size);
-               skb_reserve(skb, 2);
-       }
+       return 0;
 }
 
-/**
- *     velocity_receive_frame  -       received packet processor
- *     @vptr: velocity we are handling
- *     @idx: ring index
- *
- *     A packet has arrived. We process the packet and if appropriate
- *     pass the frame up the network stack
- */
-
-static int velocity_receive_frame(struct velocity_info *vptr, int idx)
+static void velocity_set_rxbufsize(struct velocity_info *vptr, int mtu)
 {
-       void (*pci_action)(struct pci_dev *, dma_addr_t, size_t, int);
-       struct net_device_stats *stats = &vptr->dev->stats;
-       struct velocity_rd_info *rd_info = &(vptr->rx.info[idx]);
-       struct rx_desc *rd = &(vptr->rx.ring[idx]);
-       int pkt_len = le16_to_cpu(rd->rdesc0.len) & 0x3fff;
-       struct sk_buff *skb;
-
-       if (rd->rdesc0.RSR & (RSR_STP | RSR_EDP)) {
-               VELOCITY_PRT(MSG_LEVEL_VERBOSE, KERN_ERR " %s : the received frame span multple RDs.\n", vptr->dev->name);
-               stats->rx_length_errors++;
-               return -EINVAL;
-       }
-
-       if (rd->rdesc0.RSR & RSR_MAR)
-               stats->multicast++;
-
-       skb = rd_info->skb;
-
-       pci_dma_sync_single_for_cpu(vptr->pdev, rd_info->skb_dma,
-                                   vptr->rx.buf_sz, PCI_DMA_FROMDEVICE);
-
-       /*
-        *      Drop frame not meeting IEEE 802.3
-        */
-
-       if (vptr->flags & VELOCITY_FLAGS_VAL_PKT_LEN) {
-               if (rd->rdesc0.RSR & RSR_RL) {
-                       stats->rx_length_errors++;
-                       return -EINVAL;
-               }
-       }
-
-       pci_action = pci_dma_sync_single_for_device;
-
-       velocity_rx_csum(rd, skb);
-
-       if (velocity_rx_copy(&skb, pkt_len, vptr) < 0) {
-               velocity_iph_realign(vptr, skb, pkt_len);
-               pci_action = pci_unmap_single;
-               rd_info->skb = NULL;
-       }
-
-       pci_action(vptr->pdev, rd_info->skb_dma, vptr->rx.buf_sz,
-                  PCI_DMA_FROMDEVICE);
-
-       skb_put(skb, pkt_len - 4);
-       skb->protocol = eth_type_trans(skb, vptr->dev);
-
-       if (vptr->vlgrp && (rd->rdesc0.RSR & RSR_DETAG)) {
-               vlan_hwaccel_rx(skb, vptr->vlgrp,
-                               swab16(le16_to_cpu(rd->rdesc1.PQTAG)));
-       } else
-               netif_rx(skb);
-
-       stats->rx_bytes += pkt_len;
-
-       return 0;
+       vptr->rx.buf_sz = (mtu <= ETH_DATA_LEN) ? PKT_BUF_SZ : mtu + 32;
 }
 
 /**
@@ -1589,7 +1470,6 @@ static int velocity_receive_frame(struct velocity_info *vptr, int idx)
  *     requires *64* byte alignment of the buffer which makes life
  *     less fun than would be ideal.
  */
-
 static int velocity_alloc_rx_buf(struct velocity_info *vptr, int idx)
 {
        struct rx_desc *rd = &(vptr->rx.ring[idx]);
@@ -1618,125 +1498,257 @@ static int velocity_alloc_rx_buf(struct velocity_info *vptr, int idx)
        return 0;
 }
 
-/**
- *     tx_srv          -       transmit interrupt service
- *     @vptr; Velocity
- *     @status:
- *
- *     Scan the queues looking for transmitted packets that
- *     we can complete and clean up. Update any statistics as
- *     necessary/
- */
 
-static int velocity_tx_srv(struct velocity_info *vptr, u32 status)
+static int velocity_rx_refill(struct velocity_info *vptr)
 {
-       struct tx_desc *td;
-       int qnum;
-       int full = 0;
-       int idx;
-       int works = 0;
-       struct velocity_td_info *tdinfo;
-       struct net_device_stats *stats = &vptr->dev->stats;
-
-       for (qnum = 0; qnum < vptr->tx.numq; qnum++) {
-               for (idx = vptr->tx.tail[qnum]; vptr->tx.used[qnum] > 0;
-                       idx = (idx + 1) % vptr->options.numtx) {
+       int dirty = vptr->rx.dirty, done = 0;
 
-                       /*
-                        *      Get Tx Descriptor
-                        */
-                       td = &(vptr->tx.rings[qnum][idx]);
-                       tdinfo = &(vptr->tx.infos[qnum][idx]);
+       do {
+               struct rx_desc *rd = vptr->rx.ring + dirty;
 
-                       if (td->tdesc0.len & OWNED_BY_NIC)
-                               break;
+               /* Fine for an all zero Rx desc at init time as well */
+               if (rd->rdesc0.len & OWNED_BY_NIC)
+                       break;
 
-                       if ((works++ > 15))
+               if (!vptr->rx.info[dirty].skb) {
+                       if (velocity_alloc_rx_buf(vptr, dirty) < 0)
                                break;
-
-                       if (td->tdesc0.TSR & TSR0_TERR) {
-                               stats->tx_errors++;
-                               stats->tx_dropped++;
-                               if (td->tdesc0.TSR & TSR0_CDH)
-                                       stats->tx_heartbeat_errors++;
-                               if (td->tdesc0.TSR & TSR0_CRS)
-                                       stats->tx_carrier_errors++;
-                               if (td->tdesc0.TSR & TSR0_ABT)
-                                       stats->tx_aborted_errors++;
-                               if (td->tdesc0.TSR & TSR0_OWC)
-                                       stats->tx_window_errors++;
-                       } else {
-                               stats->tx_packets++;
-                               stats->tx_bytes += tdinfo->skb->len;
-                       }
-                       velocity_free_tx_buf(vptr, tdinfo);
-                       vptr->tx.used[qnum]--;
                }
-               vptr->tx.tail[qnum] = idx;
+               done++;
+               dirty = (dirty < vptr->options.numrx - 1) ? dirty + 1 : 0;
+       } while (dirty != vptr->rx.curr);
 
-               if (AVAIL_TD(vptr, qnum) < 1) {
-                       full = 1;
-               }
-       }
-       /*
-        *      Look to see if we should kick the transmit network
-        *      layer for more work.
-        */
-       if (netif_queue_stopped(vptr->dev) && (full == 0)
-           && (!(vptr->mii_status & VELOCITY_LINK_FAIL))) {
-               netif_wake_queue(vptr->dev);
+       if (done) {
+               vptr->rx.dirty = dirty;
+               vptr->rx.filled += done;
        }
-       return works;
+
+       return done;
 }
 
 /**
- *     velocity_print_link_status      -       link status reporting
- *     @vptr: velocity to report on
+ *     velocity_free_rd_ring   -       free receive ring
+ *     @vptr: velocity to clean up
  *
- *     Turn the link status of the velocity card into a kernel log
- *     description of the new link state, detailing speed and duplex
- *     status
+ *     Free the receive buffers for each ring slot and any
+ *     attached socket buffers that need to go away.
  */
-
-static void velocity_print_link_status(struct velocity_info *vptr)
+static void velocity_free_rd_ring(struct velocity_info *vptr)
 {
+       int i;
 
-       if (vptr->mii_status & VELOCITY_LINK_FAIL) {
-               VELOCITY_PRT(MSG_LEVEL_INFO, KERN_NOTICE "%s: failed to detect cable link\n", vptr->dev->name);
-       } else if (vptr->options.spd_dpx == SPD_DPX_AUTO) {
-               VELOCITY_PRT(MSG_LEVEL_INFO, KERN_NOTICE "%s: Link auto-negotiation", vptr->dev->name);
+       if (vptr->rx.info == NULL)
+               return;
 
-               if (vptr->mii_status & VELOCITY_SPEED_1000)
-                       VELOCITY_PRT(MSG_LEVEL_INFO, " speed 1000M bps");
-               else if (vptr->mii_status & VELOCITY_SPEED_100)
-                       VELOCITY_PRT(MSG_LEVEL_INFO, " speed 100M bps");
-               else
-                       VELOCITY_PRT(MSG_LEVEL_INFO, " speed 10M bps");
+       for (i = 0; i < vptr->options.numrx; i++) {
+               struct velocity_rd_info *rd_info = &(vptr->rx.info[i]);
+               struct rx_desc *rd = vptr->rx.ring + i;
 
-               if (vptr->mii_status & VELOCITY_DUPLEX_FULL)
-                       VELOCITY_PRT(MSG_LEVEL_INFO, " full duplex\n");
-               else
-                       VELOCITY_PRT(MSG_LEVEL_INFO, " half duplex\n");
-       } else {
-               VELOCITY_PRT(MSG_LEVEL_INFO, KERN_NOTICE "%s: Link forced", vptr->dev->name);
-               switch (vptr->options.spd_dpx) {
-               case SPD_DPX_100_HALF:
-                       VELOCITY_PRT(MSG_LEVEL_INFO, " speed 100M bps half duplex\n");
-                       break;
-               case SPD_DPX_100_FULL:
-                       VELOCITY_PRT(MSG_LEVEL_INFO, " speed 100M bps full duplex\n");
-                       break;
-               case SPD_DPX_10_HALF:
-                       VELOCITY_PRT(MSG_LEVEL_INFO, " speed 10M bps half duplex\n");
-                       break;
-               case SPD_DPX_10_FULL:
-                       VELOCITY_PRT(MSG_LEVEL_INFO, " speed 10M bps full duplex\n");
-                       break;
-               default:
-                       break;
-               }
+               memset(rd, 0, sizeof(*rd));
+
+               if (!rd_info->skb)
+                       continue;
+               pci_unmap_single(vptr->pdev, rd_info->skb_dma, vptr->rx.buf_sz,
+                                PCI_DMA_FROMDEVICE);
+               rd_info->skb_dma = 0;
+
+               dev_kfree_skb(rd_info->skb);
+               rd_info->skb = NULL;
        }
-}
+
+       kfree(vptr->rx.info);
+       vptr->rx.info = NULL;
+}
+
+
+
+/**
+ *     velocity_init_rd_ring   -       set up receive ring
+ *     @vptr: velocity to configure
+ *
+ *     Allocate and set up the receive buffers for each ring slot and
+ *     assign them to the network adapter.
+ */
+static int velocity_init_rd_ring(struct velocity_info *vptr)
+{
+       int ret = -ENOMEM;
+
+       vptr->rx.info = kcalloc(vptr->options.numrx,
+                               sizeof(struct velocity_rd_info), GFP_KERNEL);
+       if (!vptr->rx.info)
+               goto out;
+
+       velocity_init_rx_ring_indexes(vptr);
+
+       if (velocity_rx_refill(vptr) != vptr->options.numrx) {
+               VELOCITY_PRT(MSG_LEVEL_ERR, KERN_ERR
+                       "%s: failed to allocate RX buffer.\n", vptr->dev->name);
+               velocity_free_rd_ring(vptr);
+               goto out;
+       }
+
+       ret = 0;
+out:
+       return ret;
+}
+
+/**
+ *     velocity_init_td_ring   -       set up transmit ring
+ *     @vptr:  velocity
+ *
+ *     Set up the transmit ring and chain the ring pointers together.
+ *     Returns zero on success or a negative posix errno code for
+ *     failure.
+ */
+static int velocity_init_td_ring(struct velocity_info *vptr)
+{
+       dma_addr_t curr;
+       int j;
+
+       /* Init the TD ring entries */
+       for (j = 0; j < vptr->tx.numq; j++) {
+               curr = vptr->tx.pool_dma[j];
+
+               vptr->tx.infos[j] = kcalloc(vptr->options.numtx,
+                                           sizeof(struct velocity_td_info),
+                                           GFP_KERNEL);
+               if (!vptr->tx.infos[j]) {
+                       while (--j >= 0)
+                               kfree(vptr->tx.infos[j]);
+                       return -ENOMEM;
+               }
+
+               vptr->tx.tail[j] = vptr->tx.curr[j] = vptr->tx.used[j] = 0;
+       }
+       return 0;
+}
+
+/**
+ *     velocity_free_dma_rings -       free PCI ring pointers
+ *     @vptr: Velocity to free from
+ *
+ *     Clean up the PCI ring buffers allocated to this velocity.
+ */
+static void velocity_free_dma_rings(struct velocity_info *vptr)
+{
+       const int size = vptr->options.numrx * sizeof(struct rx_desc) +
+               vptr->options.numtx * sizeof(struct tx_desc) * vptr->tx.numq;
+
+       pci_free_consistent(vptr->pdev, size, vptr->rx.ring, vptr->rx.pool_dma);
+}
+
+
+static int velocity_init_rings(struct velocity_info *vptr, int mtu)
+{
+       int ret;
+
+       velocity_set_rxbufsize(vptr, mtu);
+
+       ret = velocity_init_dma_rings(vptr);
+       if (ret < 0)
+               goto out;
+
+       ret = velocity_init_rd_ring(vptr);
+       if (ret < 0)
+               goto err_free_dma_rings_0;
+
+       ret = velocity_init_td_ring(vptr);
+       if (ret < 0)
+               goto err_free_rd_ring_1;
+out:
+       return ret;
+
+err_free_rd_ring_1:
+       velocity_free_rd_ring(vptr);
+err_free_dma_rings_0:
+       velocity_free_dma_rings(vptr);
+       goto out;
+}
+
+/**
+ *     velocity_free_tx_buf    -       free transmit buffer
+ *     @vptr: velocity
+ *     @tdinfo: buffer
+ *
+ *     Release an transmit buffer. If the buffer was preallocated then
+ *     recycle it, if not then unmap the buffer.
+ */
+static void velocity_free_tx_buf(struct velocity_info *vptr, struct velocity_td_info *tdinfo)
+{
+       struct sk_buff *skb = tdinfo->skb;
+       int i;
+       int pktlen;
+
+       /*
+        *      Don't unmap the pre-allocated tx_bufs
+        */
+       if (tdinfo->skb_dma) {
+
+               pktlen = max_t(unsigned int, skb->len, ETH_ZLEN);
+               for (i = 0; i < tdinfo->nskb_dma; i++) {
+                       pci_unmap_single(vptr->pdev, tdinfo->skb_dma[i], pktlen, PCI_DMA_TODEVICE);
+                       tdinfo->skb_dma[i] = 0;
+               }
+       }
+       dev_kfree_skb_irq(skb);
+       tdinfo->skb = NULL;
+}
+
+
+/*
+ *     FIXME: could we merge this with velocity_free_tx_buf ?
+ */
+static void velocity_free_td_ring_entry(struct velocity_info *vptr,
+                                                        int q, int n)
+{
+       struct velocity_td_info *td_info = &(vptr->tx.infos[q][n]);
+       int i;
+
+       if (td_info == NULL)
+               return;
+
+       if (td_info->skb) {
+               for (i = 0; i < td_info->nskb_dma; i++) {
+                       if (td_info->skb_dma[i]) {
+                               pci_unmap_single(vptr->pdev, td_info->skb_dma[i],
+                                       td_info->skb->len, PCI_DMA_TODEVICE);
+                               td_info->skb_dma[i] = 0;
+                       }
+               }
+               dev_kfree_skb(td_info->skb);
+               td_info->skb = NULL;
+       }
+}
+
+/**
+ *     velocity_free_td_ring   -       free td ring
+ *     @vptr: velocity
+ *
+ *     Free up the transmit ring for this particular velocity adapter.
+ *     We free the ring contents but not the ring itself.
+ */
+static void velocity_free_td_ring(struct velocity_info *vptr)
+{
+       int i, j;
+
+       for (j = 0; j < vptr->tx.numq; j++) {
+               if (vptr->tx.infos[j] == NULL)
+                       continue;
+               for (i = 0; i < vptr->options.numtx; i++)
+                       velocity_free_td_ring_entry(vptr, j, i);
+
+               kfree(vptr->tx.infos[j]);
+               vptr->tx.infos[j] = NULL;
+       }
+}
+
+
+static void velocity_free_rings(struct velocity_info *vptr)
+{
+       velocity_free_td_ring(vptr);
+       velocity_free_rd_ring(vptr);
+       velocity_free_dma_rings(vptr);
+}
 
 /**
  *     velocity_error  -       handle error from controller
@@ -1749,12 +1761,11 @@ static void velocity_print_link_status(struct velocity_info *vptr)
  *     the pci_device_failed logic to bounce the hardware
  *
  */
-
 static void velocity_error(struct velocity_info *vptr, int status)
 {
 
        if (status & ISR_TXSTLI) {
-               struct mac_regs __iomem * regs = vptr->mac_regs;
+               struct mac_regs __iomem *regs = vptr->mac_regs;
 
                printk(KERN_ERR "TD structure error TDindex=%hx\n", readw(&regs->TDIdx[0]));
                BYTE_REG_BITS_ON(TXESR_TDSTR, &regs->TXESR);
@@ -1766,7 +1777,7 @@ static void velocity_error(struct velocity_info *vptr, int status)
        }
 
        if (status & ISR_SRCI) {
-               struct mac_regs __iomem * regs = vptr->mac_regs;
+               struct mac_regs __iomem *regs = vptr->mac_regs;
                int linked;
 
                if (vptr->options.spd_dpx == SPD_DPX_AUTO) {
@@ -1786,11 +1797,10 @@ static void velocity_error(struct velocity_info *vptr, int status)
                        /*
                         *      Only enable CD heart beat counter in 10HD mode
                         */
-                       if (!(vptr->mii_status & VELOCITY_DUPLEX_FULL) && (vptr->mii_status & VELOCITY_SPEED_10)) {
+                       if (!(vptr->mii_status & VELOCITY_DUPLEX_FULL) && (vptr->mii_status & VELOCITY_SPEED_10))
                                BYTE_REG_BITS_OFF(TESTCFG_HBDIS, &regs->TESTCFG);
-                       } else {
+                       else
                                BYTE_REG_BITS_ON(TESTCFG_HBDIS, &regs->TESTCFG);
-                       }
                }
                /*
                 *      Get link status from PHYSR0
@@ -1828,384 +1838,277 @@ static void velocity_error(struct velocity_info *vptr, int status)
 }
 
 /**
- *     velocity_free_tx_buf    -       free transmit buffer
- *     @vptr: velocity
- *     @tdinfo: buffer
+ *     tx_srv          -       transmit interrupt service
+ *     @vptr; Velocity
+ *     @status:
  *
- *     Release an transmit buffer. If the buffer was preallocated then
- *     recycle it, if not then unmap the buffer.
+ *     Scan the queues looking for transmitted packets that
+ *     we can complete and clean up. Update any statistics as
+ *     necessary/
  */
-
-static void velocity_free_tx_buf(struct velocity_info *vptr, struct velocity_td_info *tdinfo)
+static int velocity_tx_srv(struct velocity_info *vptr, u32 status)
 {
-       struct sk_buff *skb = tdinfo->skb;
-       int i;
-       int pktlen;
-
-       /*
-        *      Don't unmap the pre-allocated tx_bufs
-        */
-       if (tdinfo->skb_dma) {
+       struct tx_desc *td;
+       int qnum;
+       int full = 0;
+       int idx;
+       int works = 0;
+       struct velocity_td_info *tdinfo;
+       struct net_device_stats *stats = &vptr->dev->stats;
 
-               pktlen = max_t(unsigned int, skb->len, 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], pktlen, PCI_DMA_TODEVICE);
-#endif
-                       tdinfo->skb_dma[i] = 0;
-               }
-       }
-       dev_kfree_skb_irq(skb);
-       tdinfo->skb = NULL;
-}
+       for (qnum = 0; qnum < vptr->tx.numq; qnum++) {
+               for (idx = vptr->tx.tail[qnum]; vptr->tx.used[qnum] > 0;
+                       idx = (idx + 1) % vptr->options.numtx) {
 
-static int velocity_init_rings(struct velocity_info *vptr, int mtu)
-{
-       int ret;
+                       /*
+                        *      Get Tx Descriptor
+                        */
+                       td = &(vptr->tx.rings[qnum][idx]);
+                       tdinfo = &(vptr->tx.infos[qnum][idx]);
 
-       velocity_set_rxbufsize(vptr, mtu);
+                       if (td->tdesc0.len & OWNED_BY_NIC)
+                               break;
 
-       ret = velocity_init_dma_rings(vptr);
-       if (ret < 0)
-               goto out;
+                       if ((works++ > 15))
+                               break;
 
-       ret = velocity_init_rd_ring(vptr);
-       if (ret < 0)
-               goto err_free_dma_rings_0;
-
-       ret = velocity_init_td_ring(vptr);
-       if (ret < 0)
-               goto err_free_rd_ring_1;
-out:
-       return ret;
+                       if (td->tdesc0.TSR & TSR0_TERR) {
+                               stats->tx_errors++;
+                               stats->tx_dropped++;
+                               if (td->tdesc0.TSR & TSR0_CDH)
+                                       stats->tx_heartbeat_errors++;
+                               if (td->tdesc0.TSR & TSR0_CRS)
+                                       stats->tx_carrier_errors++;
+                               if (td->tdesc0.TSR & TSR0_ABT)
+                                       stats->tx_aborted_errors++;
+                               if (td->tdesc0.TSR & TSR0_OWC)
+                                       stats->tx_window_errors++;
+                       } else {
+                               stats->tx_packets++;
+                               stats->tx_bytes += tdinfo->skb->len;
+                       }
+                       velocity_free_tx_buf(vptr, tdinfo);
+                       vptr->tx.used[qnum]--;
+               }
+               vptr->tx.tail[qnum] = idx;
 
-err_free_rd_ring_1:
-       velocity_free_rd_ring(vptr);
-err_free_dma_rings_0:
-       velocity_free_dma_rings(vptr);
-       goto out;
+               if (AVAIL_TD(vptr, qnum) < 1)
+                       full = 1;
+       }
+       /*
+        *      Look to see if we should kick the transmit network
+        *      layer for more work.
+        */
+       if (netif_queue_stopped(vptr->dev) && (full == 0)
+           && (!(vptr->mii_status & VELOCITY_LINK_FAIL))) {
+               netif_wake_queue(vptr->dev);
+       }
+       return works;
 }
 
-static void velocity_free_rings(struct velocity_info *vptr)
+/**
+ *     velocity_rx_csum        -       checksum process
+ *     @rd: receive packet descriptor
+ *     @skb: network layer packet buffer
+ *
+ *     Process the status bits for the received packet and determine
+ *     if the checksum was computed and verified by the hardware
+ */
+static inline void velocity_rx_csum(struct rx_desc *rd, struct sk_buff *skb)
 {
-       velocity_free_td_ring(vptr);
-       velocity_free_rd_ring(vptr);
-       velocity_free_dma_rings(vptr);
+       skb->ip_summed = CHECKSUM_NONE;
+
+       if (rd->rdesc1.CSM & CSM_IPKT) {
+               if (rd->rdesc1.CSM & CSM_IPOK) {
+                       if ((rd->rdesc1.CSM & CSM_TCPKT) ||
+                                       (rd->rdesc1.CSM & CSM_UDPKT)) {
+                               if (!(rd->rdesc1.CSM & CSM_TUPOK))
+                                       return;
+                       }
+                       skb->ip_summed = CHECKSUM_UNNECESSARY;
+               }
+       }
 }
 
 /**
- *     velocity_open           -       interface activation callback
- *     @dev: network layer device to open
- *
- *     Called when the network layer brings the interface up. Returns
- *     a negative posix error code on failure, or zero on success.
+ *     velocity_rx_copy        -       in place Rx copy for small packets
+ *     @rx_skb: network layer packet buffer candidate
+ *     @pkt_size: received data size
+ *     @rd: receive packet descriptor
+ *     @dev: network device
  *
- *     All the ring allocation and set up is done on open for this
- *     adapter to minimise memory usage when inactive
+ *     Replace the current skb that is scheduled for Rx processing by a
+ *     shorter, immediatly allocated skb, if the received packet is small
+ *     enough. This function returns a negative value if the received
+ *     packet is too big or if memory is exhausted.
  */
-
-static int velocity_open(struct net_device *dev)
+static int velocity_rx_copy(struct sk_buff **rx_skb, int pkt_size,
+                           struct velocity_info *vptr)
 {
-       struct velocity_info *vptr = netdev_priv(dev);
-       int ret;
-
-       ret = velocity_init_rings(vptr, dev->mtu);
-       if (ret < 0)
-               goto out;
-
-       /* Ensure chip is running */
-       pci_set_power_state(vptr->pdev, PCI_D0);
-
-       velocity_give_many_rx_descs(vptr);
+       int ret = -1;
+       if (pkt_size < rx_copybreak) {
+               struct sk_buff *new_skb;
 
-       velocity_init_registers(vptr, VELOCITY_INIT_COLD);
+               new_skb = netdev_alloc_skb(vptr->dev, pkt_size + 2);
+               if (new_skb) {
+                       new_skb->ip_summed = rx_skb[0]->ip_summed;
+                       skb_reserve(new_skb, 2);
+                       skb_copy_from_linear_data(*rx_skb, new_skb->data, pkt_size);
+                       *rx_skb = new_skb;
+                       ret = 0;
+               }
 
-       ret = request_irq(vptr->pdev->irq, &velocity_intr, IRQF_SHARED,
-                         dev->name, dev);
-       if (ret < 0) {
-               /* Power down the chip */
-               pci_set_power_state(vptr->pdev, PCI_D3hot);
-               velocity_free_rings(vptr);
-               goto out;
        }
-
-       mac_enable_int(vptr->mac_regs);
-       netif_start_queue(dev);
-       vptr->flags |= VELOCITY_FLAGS_OPENED;
-out:
        return ret;
 }
 
 /**
- *     velocity_change_mtu     -       MTU change callback
- *     @dev: network device
- *     @new_mtu: desired MTU
+ *     velocity_iph_realign    -       IP header alignment
+ *     @vptr: velocity we are handling
+ *     @skb: network layer packet buffer
+ *     @pkt_size: received data size
  *
- *     Handle requests from the networking layer for MTU change on
- *     this interface. It gets called on a change by the network layer.
- *     Return zero for success or negative posix error code.
+ *     Align IP header on a 2 bytes boundary. This behavior can be
+ *     configured by the user.
  */
-
-static int velocity_change_mtu(struct net_device *dev, int new_mtu)
+static inline void velocity_iph_realign(struct velocity_info *vptr,
+                                       struct sk_buff *skb, int pkt_size)
 {
-       struct velocity_info *vptr = netdev_priv(dev);
-       int ret = 0;
-
-       if ((new_mtu < VELOCITY_MIN_MTU) || new_mtu > (VELOCITY_MAX_MTU)) {
-               VELOCITY_PRT(MSG_LEVEL_ERR, KERN_NOTICE "%s: Invalid MTU.\n",
-                               vptr->dev->name);
-               ret = -EINVAL;
-               goto out_0;
-       }
-
-       if (!netif_running(dev)) {
-               dev->mtu = new_mtu;
-               goto out_0;
+       if (vptr->flags & VELOCITY_FLAGS_IP_ALIGN) {
+               memmove(skb->data + 2, skb->data, pkt_size);
+               skb_reserve(skb, 2);
        }
+}
 
-       if (dev->mtu != new_mtu) {
-               struct velocity_info *tmp_vptr;
-               unsigned long flags;
-               struct rx_info rx;
-               struct tx_info tx;
 
-               tmp_vptr = kzalloc(sizeof(*tmp_vptr), GFP_KERNEL);
-               if (!tmp_vptr) {
-                       ret = -ENOMEM;
-                       goto out_0;
-               }
+/**
+ *     velocity_receive_frame  -       received packet processor
+ *     @vptr: velocity we are handling
+ *     @idx: ring index
+ *
+ *     A packet has arrived. We process the packet and if appropriate
+ *     pass the frame up the network stack
+ */
+static int velocity_receive_frame(struct velocity_info *vptr, int idx)
+{
+       void (*pci_action)(struct pci_dev *, dma_addr_t, size_t, int);
+       struct net_device_stats *stats = &vptr->dev->stats;
+       struct velocity_rd_info *rd_info = &(vptr->rx.info[idx]);
+       struct rx_desc *rd = &(vptr->rx.ring[idx]);
+       int pkt_len = le16_to_cpu(rd->rdesc0.len) & 0x3fff;
+       struct sk_buff *skb;
 
-               tmp_vptr->dev = dev;
-               tmp_vptr->pdev = vptr->pdev;
-               tmp_vptr->options = vptr->options;
-               tmp_vptr->tx.numq = vptr->tx.numq;
+       if (rd->rdesc0.RSR & (RSR_STP | RSR_EDP)) {
+               VELOCITY_PRT(MSG_LEVEL_VERBOSE, KERN_ERR " %s : the received frame span multple RDs.\n", vptr->dev->name);
+               stats->rx_length_errors++;
+               return -EINVAL;
+       }
 
-               ret = velocity_init_rings(tmp_vptr, new_mtu);
-               if (ret < 0)
-                       goto out_free_tmp_vptr_1;
+       if (rd->rdesc0.RSR & RSR_MAR)
+               stats->multicast++;
 
-               spin_lock_irqsave(&vptr->lock, flags);
+       skb = rd_info->skb;
 
-               netif_stop_queue(dev);
-               velocity_shutdown(vptr);
+       pci_dma_sync_single_for_cpu(vptr->pdev, rd_info->skb_dma,
+                                   vptr->rx.buf_sz, PCI_DMA_FROMDEVICE);
 
-               rx = vptr->rx;
-               tx = vptr->tx;
+       /*
+        *      Drop frame not meeting IEEE 802.3
+        */
 
-               vptr->rx = tmp_vptr->rx;
-               vptr->tx = tmp_vptr->tx;
+       if (vptr->flags & VELOCITY_FLAGS_VAL_PKT_LEN) {
+               if (rd->rdesc0.RSR & RSR_RL) {
+                       stats->rx_length_errors++;
+                       return -EINVAL;
+               }
+       }
 
-               tmp_vptr->rx = rx;
-               tmp_vptr->tx = tx;
+       pci_action = pci_dma_sync_single_for_device;
 
-               dev->mtu = new_mtu;
+       velocity_rx_csum(rd, skb);
 
-               velocity_give_many_rx_descs(vptr);
+       if (velocity_rx_copy(&skb, pkt_len, vptr) < 0) {
+               velocity_iph_realign(vptr, skb, pkt_len);
+               pci_action = pci_unmap_single;
+               rd_info->skb = NULL;
+       }
 
-               velocity_init_registers(vptr, VELOCITY_INIT_COLD);
+       pci_action(vptr->pdev, rd_info->skb_dma, vptr->rx.buf_sz,
+                  PCI_DMA_FROMDEVICE);
 
-               mac_enable_int(vptr->mac_regs);
-               netif_start_queue(dev);
+       skb_put(skb, pkt_len - 4);
+       skb->protocol = eth_type_trans(skb, vptr->dev);
 
-               spin_unlock_irqrestore(&vptr->lock, flags);
+       if (vptr->vlgrp && (rd->rdesc0.RSR & RSR_DETAG)) {
+               vlan_hwaccel_rx(skb, vptr->vlgrp,
+                               swab16(le16_to_cpu(rd->rdesc1.PQTAG)));
+       } else
+               netif_rx(skb);
 
-               velocity_free_rings(tmp_vptr);
+       stats->rx_bytes += pkt_len;
 
-out_free_tmp_vptr_1:
-               kfree(tmp_vptr);
-       }
-out_0:
-       return ret;
+       return 0;
 }
 
+
 /**
- *     velocity_shutdown       -       shut down the chip
- *     @vptr: velocity to deactivate
+ *     velocity_rx_srv         -       service RX interrupt
+ *     @vptr: velocity
+ *     @status: adapter status (unused)
  *
- *     Shuts down the internal operations of the velocity and
- *     disables interrupts, autopolling, transmit and receive
+ *     Walk the receive ring of the velocity adapter and remove
+ *     any received packets from the receive queue. Hand the ring
+ *     slots back to the adapter for reuse.
  */
-
-static void velocity_shutdown(struct velocity_info *vptr)
-{
-       struct mac_regs __iomem * regs = vptr->mac_regs;
-       mac_disable_int(regs);
-       writel(CR0_STOP, &regs->CR0Set);
-       writew(0xFFFF, &regs->TDCSRClr);
-       writeb(0xFF, &regs->RDCSRClr);
-       safe_disable_mii_autopoll(regs);
-       mac_clear_isr(regs);
-}
-
-/**
- *     velocity_close          -       close adapter callback
- *     @dev: network device
- *
- *     Callback from the network layer when the velocity is being
- *     deactivated by the network layer
- */
-
-static int velocity_close(struct net_device *dev)
-{
-       struct velocity_info *vptr = netdev_priv(dev);
-
-       netif_stop_queue(dev);
-       velocity_shutdown(vptr);
-
-       if (vptr->flags & VELOCITY_FLAGS_WOL_ENABLED)
-               velocity_get_ip(vptr);
-       if (dev->irq != 0)
-               free_irq(dev->irq, dev);
-
-       /* Power down the chip */
-       pci_set_power_state(vptr->pdev, PCI_D3hot);
-
-       velocity_free_rings(vptr);
-
-       vptr->flags &= (~VELOCITY_FLAGS_OPENED);
-       return 0;
-}
-
-/**
- *     velocity_xmit           -       transmit packet callback
- *     @skb: buffer to transmit
- *     @dev: network device
- *
- *     Called by the networ layer to request a packet is queued to
- *     the velocity. Returns zero on success.
- */
-
-static int velocity_xmit(struct sk_buff *skb, struct net_device *dev)
+static int velocity_rx_srv(struct velocity_info *vptr, int status)
 {
-       struct velocity_info *vptr = netdev_priv(dev);
-       int qnum = 0;
-       struct tx_desc *td_ptr;
-       struct velocity_td_info *tdinfo;
-       unsigned long flags;
-       int pktlen;
-       __le16 len;
-       int index;
-
-
-       if (skb_padto(skb, ETH_ZLEN))
-               goto out;
-       pktlen = max_t(unsigned int, skb->len, ETH_ZLEN);
-
-       len = cpu_to_le16(pktlen);
-
-#ifdef VELOCITY_ZERO_COPY_SUPPORT
-       if (skb_shinfo(skb)->nr_frags > 6 && __skb_linearize(skb)) {
-               kfree_skb(skb);
-               return 0;
-       }
-#endif
-
-       spin_lock_irqsave(&vptr->lock, flags);
-
-       index = vptr->tx.curr[qnum];
-       td_ptr = &(vptr->tx.rings[qnum][index]);
-       tdinfo = &(vptr->tx.infos[qnum][index]);
-
-       td_ptr->tdesc1.TCR = TCR0_TIC;
-       td_ptr->td_buf[0].size &= ~TD_QUEUE;
-
-#ifdef VELOCITY_ZERO_COPY_SUPPORT
-       if (skb_shinfo(skb)->nr_frags > 0) {
-               int nfrags = skb_shinfo(skb)->nr_frags;
-               tdinfo->skb = skb;
-               if (nfrags > 6) {
-                       skb_copy_from_linear_data(skb, tdinfo->buf, skb->len);
-                       tdinfo->skb_dma[0] = tdinfo->buf_dma;
-                       td_ptr->tdesc0.len = len;
-                       td_ptr->tx.buf[0].pa_low = cpu_to_le32(tdinfo->skb_dma[0]);
-                       td_ptr->tx.buf[0].pa_high = 0;
-                       td_ptr->tx.buf[0].size = len;   /* queue is 0 anyway */
-                       tdinfo->nskb_dma = 1;
-               } else {
-                       int i = 0;
-                       tdinfo->nskb_dma = 0;
-                       tdinfo->skb_dma[i] = pci_map_single(vptr->pdev, skb->data,
-                                               skb_headlen(skb), PCI_DMA_TODEVICE);
-
-                       td_ptr->tdesc0.len = len;
+       struct net_device_stats *stats = &vptr->dev->stats;
+       int rd_curr = vptr->rx.curr;
+       int works = 0;
 
-                       /* FIXME: support 48bit DMA later */
-                       td_ptr->tx.buf[i].pa_low = cpu_to_le32(tdinfo->skb_dma);
-                       td_ptr->tx.buf[i].pa_high = 0;
-                       td_ptr->tx.buf[i].size = cpu_to_le16(skb_headlen(skb));
+       do {
+               struct rx_desc *rd = vptr->rx.ring + rd_curr;
 
-                       for (i = 0; i < nfrags; i++) {
-                               skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
-                               void *addr = (void *)page_address(frag->page) + frag->page_offset;
+               if (!vptr->rx.info[rd_curr].skb)
+                       break;
 
-                               tdinfo->skb_dma[i + 1] = pci_map_single(vptr->pdev, addr, frag->size, PCI_DMA_TODEVICE);
+               if (rd->rdesc0.len & OWNED_BY_NIC)
+                       break;
 
-                               td_ptr->tx.buf[i + 1].pa_low = cpu_to_le32(tdinfo->skb_dma[i + 1]);
-                               td_ptr->tx.buf[i + 1].pa_high = 0;
-                               td_ptr->tx.buf[i + 1].size = cpu_to_le16(frag->size);
-                       }
-                       tdinfo->nskb_dma = i - 1;
-               }
+               rmb();
 
-       } else
-#endif
-       {
                /*
-                *      Map the linear network buffer into PCI space and
-                *      add it to the transmit ring.
+                *      Don't drop CE or RL error frame although RXOK is off
                 */
-               tdinfo->skb = skb;
-               tdinfo->skb_dma[0] = pci_map_single(vptr->pdev, skb->data, pktlen, PCI_DMA_TODEVICE);
-               td_ptr->tdesc0.len = len;
-               td_ptr->td_buf[0].pa_low = cpu_to_le32(tdinfo->skb_dma[0]);
-               td_ptr->td_buf[0].pa_high = 0;
-               td_ptr->td_buf[0].size = len;
-               tdinfo->nskb_dma = 1;
-       }
-       td_ptr->tdesc1.cmd = TCPLS_NORMAL + (tdinfo->nskb_dma + 1) * 16;
+               if (rd->rdesc0.RSR & (RSR_RXOK | RSR_CE | RSR_RL)) {
+                       if (velocity_receive_frame(vptr, rd_curr) < 0)
+                               stats->rx_dropped++;
+               } else {
+                       if (rd->rdesc0.RSR & RSR_CRC)
+                               stats->rx_crc_errors++;
+                       if (rd->rdesc0.RSR & RSR_FAE)
+                               stats->rx_frame_errors++;
 
-       if (vptr->vlgrp && vlan_tx_tag_present(skb)) {
-               td_ptr->tdesc1.vlan = cpu_to_le16(vlan_tx_tag_get(skb));
-               td_ptr->tdesc1.TCR |= TCR0_VETAG;
-       }
+                       stats->rx_dropped++;
+               }
 
-       /*
-        *      Handle hardware checksum
-        */
-       if ((vptr->flags & VELOCITY_FLAGS_TX_CSUM)
-                                && (skb->ip_summed == CHECKSUM_PARTIAL)) {
-               const struct iphdr *ip = ip_hdr(skb);
-               if (ip->protocol == IPPROTO_TCP)
-                       td_ptr->tdesc1.TCR |= TCR0_TCPCK;
-               else if (ip->protocol == IPPROTO_UDP)
-                       td_ptr->tdesc1.TCR |= (TCR0_UDPCK);
-               td_ptr->tdesc1.TCR |= TCR0_IPCK;
-       }
-       {
+               rd->size |= RX_INTEN;
 
-               int prev = index - 1;
+               rd_curr++;
+               if (rd_curr >= vptr->options.numrx)
+                       rd_curr = 0;
+       } while (++works <= 15);
 
-               if (prev < 0)
-                       prev = vptr->options.numtx - 1;
-               td_ptr->tdesc0.len |= OWNED_BY_NIC;
-               vptr->tx.used[qnum]++;
-               vptr->tx.curr[qnum] = (index + 1) % vptr->options.numtx;
+       vptr->rx.curr = rd_curr;
 
-               if (AVAIL_TD(vptr, qnum) < 1)
-                       netif_stop_queue(dev);
+       if ((works > 0) && (velocity_rx_refill(vptr) > 0))
+               velocity_give_many_rx_descs(vptr);
 
-               td_ptr = &(vptr->tx.rings[qnum][prev]);
-               td_ptr->td_buf[0].size |= TD_QUEUE;
-               mac_tx_queue_wake(vptr->mac_regs, qnum);
-       }
-       dev->trans_start = jiffies;
-       spin_unlock_irqrestore(&vptr->lock, flags);
-out:
-       return NETDEV_TX_OK;
+       VAR_USED(stats);
+       return works;
 }
 
+
 /**
  *     velocity_intr           -       interrupt callback
  *     @irq: interrupt number
@@ -2216,7 +2119,6 @@ out:
  *     and need to identify initially if we are, and if not exit as
  *     efficiently as possible.
  */
-
 static irqreturn_t velocity_intr(int irq, void *dev_instance)
 {
        struct net_device *dev = dev_instance;
@@ -2250,8 +2152,7 @@ static irqreturn_t velocity_intr(int irq, void *dev_instance)
                if (isr_status & (ISR_PTXI | ISR_PPTXI))
                        max_count += velocity_tx_srv(vptr, isr_status);
                isr_status = mac_read_isr(vptr->mac_regs);
-               if (max_count > vptr->options.int_works)
-               {
+               if (max_count > vptr->options.int_works) {
                        printk(KERN_WARNING "%s: excessive work at interrupt.\n",
                                dev->name);
                        max_count = 0;
@@ -2263,93 +2164,189 @@ static irqreturn_t velocity_intr(int irq, void *dev_instance)
 
 }
 
-
 /**
- *     velocity_set_multi      -       filter list change callback
- *     @dev: network device
+ *     velocity_open           -       interface activation callback
+ *     @dev: network layer device to open
  *
- *     Called by the network layer when the filter lists need to change
- *     for a velocity adapter. Reload the CAMs with the new address
- *     filter ruleset.
+ *     Called when the network layer brings the interface up. Returns
+ *     a negative posix error code on failure, or zero on success.
+ *
+ *     All the ring allocation and set up is done on open for this
+ *     adapter to minimise memory usage when inactive
  */
-
-static void velocity_set_multi(struct net_device *dev)
+static int velocity_open(struct net_device *dev)
 {
        struct velocity_info *vptr = netdev_priv(dev);
-       struct mac_regs __iomem * regs = vptr->mac_regs;
-       u8 rx_mode;
-       int i;
-       struct dev_mc_list *mclist;
+       int ret;
 
-       if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */
-               writel(0xffffffff, &regs->MARCAM[0]);
-               writel(0xffffffff, &regs->MARCAM[4]);
-               rx_mode = (RCR_AM | RCR_AB | RCR_PROM);
-       } else if ((dev->mc_count > vptr->multicast_limit)
-                  || (dev->flags & IFF_ALLMULTI)) {
-               writel(0xffffffff, &regs->MARCAM[0]);
-               writel(0xffffffff, &regs->MARCAM[4]);
-               rx_mode = (RCR_AM | RCR_AB);
-       } else {
-               int offset = MCAM_SIZE - vptr->multicast_limit;
-               mac_get_cam_mask(regs, vptr->mCAMmask);
+       ret = velocity_init_rings(vptr, dev->mtu);
+       if (ret < 0)
+               goto out;
 
-               for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; i++, mclist = mclist->next) {
-                       mac_set_cam(regs, i + offset, mclist->dmi_addr);
-                       vptr->mCAMmask[(offset + i) / 8] |= 1 << ((offset + i) & 7);
-               }
+       /* Ensure chip is running */
+       pci_set_power_state(vptr->pdev, PCI_D0);
 
-               mac_set_cam_mask(regs, vptr->mCAMmask);
-               rx_mode = RCR_AM | RCR_AB | RCR_AP;
+       velocity_give_many_rx_descs(vptr);
+
+       velocity_init_registers(vptr, VELOCITY_INIT_COLD);
+
+       ret = request_irq(vptr->pdev->irq, &velocity_intr, IRQF_SHARED,
+                         dev->name, dev);
+       if (ret < 0) {
+               /* Power down the chip */
+               pci_set_power_state(vptr->pdev, PCI_D3hot);
+               velocity_free_rings(vptr);
+               goto out;
        }
-       if (dev->mtu > 1500)
-               rx_mode |= RCR_AL;
 
-       BYTE_REG_BITS_ON(rx_mode, &regs->RCR);
+       mac_enable_int(vptr->mac_regs);
+       netif_start_queue(dev);
+       vptr->flags |= VELOCITY_FLAGS_OPENED;
+out:
+       return ret;
+}
 
+/**
+ *     velocity_shutdown       -       shut down the chip
+ *     @vptr: velocity to deactivate
+ *
+ *     Shuts down the internal operations of the velocity and
+ *     disables interrupts, autopolling, transmit and receive
+ */
+static void velocity_shutdown(struct velocity_info *vptr)
+{
+       struct mac_regs __iomem *regs = vptr->mac_regs;
+       mac_disable_int(regs);
+       writel(CR0_STOP, &regs->CR0Set);
+       writew(0xFFFF, &regs->TDCSRClr);
+       writeb(0xFF, &regs->RDCSRClr);
+       safe_disable_mii_autopoll(regs);
+       mac_clear_isr(regs);
 }
 
 /**
- *     velocity_get_status     -       statistics callback
+ *     velocity_change_mtu     -       MTU change callback
  *     @dev: network device
+ *     @new_mtu: desired MTU
  *
- *     Callback from the network layer to allow driver statistics
- *     to be resynchronized with hardware collected state. In the
- *     case of the velocity we need to pull the MIB counters from
- *     the hardware into the counters before letting the network
- *     layer display them.
+ *     Handle requests from the networking layer for MTU change on
+ *     this interface. It gets called on a change by the network layer.
+ *     Return zero for success or negative posix error code.
  */
-
-static struct net_device_stats *velocity_get_stats(struct net_device *dev)
+static int velocity_change_mtu(struct net_device *dev, int new_mtu)
 {
        struct velocity_info *vptr = netdev_priv(dev);
+       int ret = 0;
 
-       /* If the hardware is down, don't touch MII */
-       if(!netif_running(dev))
-               return &dev->stats;
-
-       spin_lock_irq(&vptr->lock);
-       velocity_update_hw_mibs(vptr);
-       spin_unlock_irq(&vptr->lock);
-
-       dev->stats.rx_packets = vptr->mib_counter[HW_MIB_ifRxAllPkts];
-       dev->stats.rx_errors = vptr->mib_counter[HW_MIB_ifRxErrorPkts];
-       dev->stats.rx_length_errors = vptr->mib_counter[HW_MIB_ifInRangeLengthErrors];
+       if ((new_mtu < VELOCITY_MIN_MTU) || new_mtu > (VELOCITY_MAX_MTU)) {
+               VELOCITY_PRT(MSG_LEVEL_ERR, KERN_NOTICE "%s: Invalid MTU.\n",
+                               vptr->dev->name);
+               ret = -EINVAL;
+               goto out_0;
+       }
 
-//  unsigned long   rx_dropped;     /* no space in linux buffers    */
-       dev->stats.collisions = vptr->mib_counter[HW_MIB_ifTxEtherCollisions];
-       /* detailed rx_errors: */
-//  unsigned long   rx_length_errors;
-//  unsigned long   rx_over_errors;     /* receiver ring buff overflow  */
-       dev->stats.rx_crc_errors = vptr->mib_counter[HW_MIB_ifRxPktCRCE];
-//  unsigned long   rx_frame_errors;    /* recv'd frame alignment error */
-//  unsigned long   rx_fifo_errors;     /* recv'r fifo overrun      */
-//  unsigned long   rx_missed_errors;   /* receiver missed packet   */
+       if (!netif_running(dev)) {
+               dev->mtu = new_mtu;
+               goto out_0;
+       }
 
-       /* detailed tx_errors */
-//  unsigned long   tx_fifo_errors;
+       if (dev->mtu != new_mtu) {
+               struct velocity_info *tmp_vptr;
+               unsigned long flags;
+               struct rx_info rx;
+               struct tx_info tx;
 
-       return &dev->stats;
+               tmp_vptr = kzalloc(sizeof(*tmp_vptr), GFP_KERNEL);
+               if (!tmp_vptr) {
+                       ret = -ENOMEM;
+                       goto out_0;
+               }
+
+               tmp_vptr->dev = dev;
+               tmp_vptr->pdev = vptr->pdev;
+               tmp_vptr->options = vptr->options;
+               tmp_vptr->tx.numq = vptr->tx.numq;
+
+               ret = velocity_init_rings(tmp_vptr, new_mtu);
+               if (ret < 0)
+                       goto out_free_tmp_vptr_1;
+
+               spin_lock_irqsave(&vptr->lock, flags);
+
+               netif_stop_queue(dev);
+               velocity_shutdown(vptr);
+
+               rx = vptr->rx;
+               tx = vptr->tx;
+
+               vptr->rx = tmp_vptr->rx;
+               vptr->tx = tmp_vptr->tx;
+
+               tmp_vptr->rx = rx;
+               tmp_vptr->tx = tx;
+
+               dev->mtu = new_mtu;
+
+               velocity_give_many_rx_descs(vptr);
+
+               velocity_init_registers(vptr, VELOCITY_INIT_COLD);
+
+               mac_enable_int(vptr->mac_regs);
+               netif_start_queue(dev);
+
+               spin_unlock_irqrestore(&vptr->lock, flags);
+
+               velocity_free_rings(tmp_vptr);
+
+out_free_tmp_vptr_1:
+               kfree(tmp_vptr);
+       }
+out_0:
+       return ret;
+}
+
+/**
+ *     velocity_mii_ioctl              -       MII ioctl handler
+ *     @dev: network device
+ *     @ifr: the ifreq block for the ioctl
+ *     @cmd: the command
+ *
+ *     Process MII requests made via ioctl from the network layer. These
+ *     are used by tools like kudzu to interrogate the link state of the
+ *     hardware
+ */
+static int velocity_mii_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+       struct velocity_info *vptr = netdev_priv(dev);
+       struct mac_regs __iomem *regs = vptr->mac_regs;
+       unsigned long flags;
+       struct mii_ioctl_data *miidata = if_mii(ifr);
+       int err;
+
+       switch (cmd) {
+       case SIOCGMIIPHY:
+               miidata->phy_id = readb(&regs->MIIADR) & 0x1f;
+               break;
+       case SIOCGMIIREG:
+               if (!capable(CAP_NET_ADMIN))
+                       return -EPERM;
+               if (velocity_mii_read(vptr->mac_regs, miidata->reg_num & 0x1f, &(miidata->val_out)) < 0)
+                       return -ETIMEDOUT;
+               break;
+       case SIOCSMIIREG:
+               if (!capable(CAP_NET_ADMIN))
+                       return -EPERM;
+               spin_lock_irqsave(&vptr->lock, flags);
+               err = velocity_mii_write(vptr->mac_regs, miidata->reg_num & 0x1f, miidata->val_in);
+               spin_unlock_irqrestore(&vptr->lock, flags);
+               check_connection_type(vptr->mac_regs);
+               if (err)
+                       return err;
+               break;
+       default:
+               return -EOPNOTSUPP;
+       }
+       return 0;
 }
 
 
@@ -2362,7 +2359,6 @@ static struct net_device_stats *velocity_get_stats(struct net_device *dev)
  *     Called when the user issues an ioctl request to the network
  *     device in question. The velocity interface supports MII.
  */
-
 static int velocity_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
        struct velocity_info *vptr = netdev_priv(dev);
@@ -2391,888 +2387,425 @@ static int velocity_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
        return ret;
 }
 
-/*
- *     Definition for our device driver. The PCI layer interface
- *     uses this to handle all our card discover and plugging
- */
-
-static struct pci_driver velocity_driver = {
-      .name    = VELOCITY_NAME,
-      .id_table        = velocity_id_table,
-      .probe   = velocity_found1,
-      .remove  = __devexit_p(velocity_remove1),
-#ifdef CONFIG_PM
-      .suspend = velocity_suspend,
-      .resume  = velocity_resume,
-#endif
-};
-
 /**
- *     velocity_init_module    -       load time function
+ *     velocity_get_status     -       statistics callback
+ *     @dev: network device
  *
- *     Called when the velocity module is loaded. The PCI driver
- *     is registered with the PCI layer, and in turn will call
- *     the probe functions for each velocity adapter installed
- *     in the system.
+ *     Callback from the network layer to allow driver statistics
+ *     to be resynchronized with hardware collected state. In the
+ *     case of the velocity we need to pull the MIB counters from
+ *     the hardware into the counters before letting the network
+ *     layer display them.
  */
-
-static int __init velocity_init_module(void)
+static struct net_device_stats *velocity_get_stats(struct net_device *dev)
 {
-       int ret;
+       struct velocity_info *vptr = netdev_priv(dev);
 
-       velocity_register_notifier();
-       ret = pci_register_driver(&velocity_driver);
-       if (ret < 0)
-               velocity_unregister_notifier();
-       return ret;
+       /* If the hardware is down, don't touch MII */
+       if (!netif_running(dev))
+               return &dev->stats;
+
+       spin_lock_irq(&vptr->lock);
+       velocity_update_hw_mibs(vptr);
+       spin_unlock_irq(&vptr->lock);
+
+       dev->stats.rx_packets = vptr->mib_counter[HW_MIB_ifRxAllPkts];
+       dev->stats.rx_errors = vptr->mib_counter[HW_MIB_ifRxErrorPkts];
+       dev->stats.rx_length_errors = vptr->mib_counter[HW_MIB_ifInRangeLengthErrors];
+
+//  unsigned long   rx_dropped;     /* no space in linux buffers    */
+       dev->stats.collisions = vptr->mib_counter[HW_MIB_ifTxEtherCollisions];
+       /* detailed rx_errors: */
+//  unsigned long   rx_length_errors;
+//  unsigned long   rx_over_errors;     /* receiver ring buff overflow  */
+       dev->stats.rx_crc_errors = vptr->mib_counter[HW_MIB_ifRxPktCRCE];
+//  unsigned long   rx_frame_errors;    /* recv'd frame alignment error */
+//  unsigned long   rx_fifo_errors;     /* recv'r fifo overrun      */
+//  unsigned long   rx_missed_errors;   /* receiver missed packet   */
+
+       /* detailed tx_errors */
+//  unsigned long   tx_fifo_errors;
+
+       return &dev->stats;
 }
 
 /**
- *     velocity_cleanup        -       module unload
+ *     velocity_close          -       close adapter callback
+ *     @dev: network device
  *
- *     When the velocity hardware is unloaded this function is called.
- *     It will clean up the notifiers and the unregister the PCI
- *     driver interface for this hardware. This in turn cleans up
- *     all discovered interfaces before returning from the function
+ *     Callback from the network layer when the velocity is being
+ *     deactivated by the network layer
  */
-
-static void __exit velocity_cleanup_module(void)
+static int velocity_close(struct net_device *dev)
 {
-       velocity_unregister_notifier();
-       pci_unregister_driver(&velocity_driver);
-}
+       struct velocity_info *vptr = netdev_priv(dev);
 
-module_init(velocity_init_module);
-module_exit(velocity_cleanup_module);
+       netif_stop_queue(dev);
+       velocity_shutdown(vptr);
+
+       if (vptr->flags & VELOCITY_FLAGS_WOL_ENABLED)
+               velocity_get_ip(vptr);
+       if (dev->irq != 0)
+               free_irq(dev->irq, dev);
 
+       /* Power down the chip */
+       pci_set_power_state(vptr->pdev, PCI_D3hot);
 
-/*
- * MII access , media link mode setting functions
- */
+       velocity_free_rings(vptr);
 
+       vptr->flags &= (~VELOCITY_FLAGS_OPENED);
+       return 0;
+}
 
 /**
- *     mii_init        -       set up MII
- *     @vptr: velocity adapter
- *     @mii_status:  links tatus
+ *     velocity_xmit           -       transmit packet callback
+ *     @skb: buffer to transmit
+ *     @dev: network device
  *
- *     Set up the PHY for the current link state.
+ *     Called by the networ layer to request a packet is queued to
+ *     the velocity. Returns zero on success.
  */
-
-static void mii_init(struct velocity_info *vptr, u32 mii_status)
+static int velocity_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-       u16 BMCR;
+       struct velocity_info *vptr = netdev_priv(dev);
+       int qnum = 0;
+       struct tx_desc *td_ptr;
+       struct velocity_td_info *tdinfo;
+       unsigned long flags;
+       int pktlen;
+       __le16 len;
+       int index;
 
-       switch (PHYID_GET_PHY_ID(vptr->phy_id)) {
-       case PHYID_CICADA_CS8201:
-               /*
-                *      Reset to hardware default
-                */
-               MII_REG_BITS_OFF((ANAR_ASMDIR | ANAR_PAUSE), MII_REG_ANAR, vptr->mac_regs);
-               /*
-                *      Turn on ECHODIS bit in NWay-forced full mode and turn it
-                *      off it in NWay-forced half mode for NWay-forced v.s.
-                *      legacy-forced issue.
-                */
-               if (vptr->mii_status & VELOCITY_DUPLEX_FULL)
-                       MII_REG_BITS_ON(TCSR_ECHODIS, MII_REG_TCSR, vptr->mac_regs);
-               else
-                       MII_REG_BITS_OFF(TCSR_ECHODIS, MII_REG_TCSR, vptr->mac_regs);
-               /*
-                *      Turn on Link/Activity LED enable bit for CIS8201
-                */
-               MII_REG_BITS_ON(PLED_LALBE, MII_REG_PLED, vptr->mac_regs);
-               break;
-       case PHYID_VT3216_32BIT:
-       case PHYID_VT3216_64BIT:
-               /*
-                *      Reset to hardware default
-                */
-               MII_REG_BITS_ON((ANAR_ASMDIR | ANAR_PAUSE), MII_REG_ANAR, vptr->mac_regs);
-               /*
-                *      Turn on ECHODIS bit in NWay-forced full mode and turn it
-                *      off it in NWay-forced half mode for NWay-forced v.s.
-                *      legacy-forced issue
-                */
-               if (vptr->mii_status & VELOCITY_DUPLEX_FULL)
-                       MII_REG_BITS_ON(TCSR_ECHODIS, MII_REG_TCSR, vptr->mac_regs);
-               else
-                       MII_REG_BITS_OFF(TCSR_ECHODIS, MII_REG_TCSR, vptr->mac_regs);
-               break;
-
-       case PHYID_MARVELL_1000:
-       case PHYID_MARVELL_1000S:
-               /*
-                *      Assert CRS on Transmit
-                */
-               MII_REG_BITS_ON(PSCR_ACRSTX, MII_REG_PSCR, vptr->mac_regs);
-               /*
-                *      Reset to hardware default
-                */
-               MII_REG_BITS_ON((ANAR_ASMDIR | ANAR_PAUSE), MII_REG_ANAR, vptr->mac_regs);
-               break;
-       default:
-               ;
-       }
-       velocity_mii_read(vptr->mac_regs, MII_REG_BMCR, &BMCR);
-       if (BMCR & BMCR_ISO) {
-               BMCR &= ~BMCR_ISO;
-               velocity_mii_write(vptr->mac_regs, MII_REG_BMCR, BMCR);
-       }
-}
-
-/**
- *     safe_disable_mii_autopoll       -       autopoll off
- *     @regs: velocity registers
- *
- *     Turn off the autopoll and wait for it to disable on the chip
- */
-
-static void safe_disable_mii_autopoll(struct mac_regs __iomem * regs)
-{
-       u16 ww;
+       if (skb_padto(skb, ETH_ZLEN))
+               goto out;
+       pktlen = max_t(unsigned int, skb->len, ETH_ZLEN);
 
-       /*  turn off MAUTO */
-       writeb(0, &regs->MIICR);
-       for (ww = 0; ww < W_MAX_TIMEOUT; ww++) {
-               udelay(1);
-               if (BYTE_REG_BITS_IS_ON(MIISR_MIDLE, &regs->MIISR))
-                       break;
-       }
-}
+       len = cpu_to_le16(pktlen);
 
-/**
- *     enable_mii_autopoll     -       turn on autopolling
- *     @regs: velocity registers
- *
- *     Enable the MII link status autopoll feature on the Velocity
- *     hardware. Wait for it to enable.
- */
+       spin_lock_irqsave(&vptr->lock, flags);
 
-static void enable_mii_autopoll(struct mac_regs __iomem * regs)
-{
-       int ii;
+       index = vptr->tx.curr[qnum];
+       td_ptr = &(vptr->tx.rings[qnum][index]);
+       tdinfo = &(vptr->tx.infos[qnum][index]);
 
-       writeb(0, &(regs->MIICR));
-       writeb(MIIADR_SWMPL, &regs->MIIADR);
+       td_ptr->tdesc1.TCR = TCR0_TIC;
+       td_ptr->td_buf[0].size &= ~TD_QUEUE;
 
-       for (ii = 0; ii < W_MAX_TIMEOUT; ii++) {
-               udelay(1);
-               if (BYTE_REG_BITS_IS_ON(MIISR_MIDLE, &regs->MIISR))
-                       break;
-       }
+       /*
+        *      Map the linear network buffer into PCI space and
+        *      add it to the transmit ring.
+        */
+       tdinfo->skb = skb;
+       tdinfo->skb_dma[0] = pci_map_single(vptr->pdev, skb->data, pktlen, PCI_DMA_TODEVICE);
+       td_ptr->tdesc0.len = len;
+       td_ptr->td_buf[0].pa_low = cpu_to_le32(tdinfo->skb_dma[0]);
+       td_ptr->td_buf[0].pa_high = 0;
+       td_ptr->td_buf[0].size = len;
+       tdinfo->nskb_dma = 1;
 
-       writeb(MIICR_MAUTO, &regs->MIICR);
+       td_ptr->tdesc1.cmd = TCPLS_NORMAL + (tdinfo->nskb_dma + 1) * 16;
 
-       for (ii = 0; ii < W_MAX_TIMEOUT; ii++) {
-               udelay(1);
-               if (!BYTE_REG_BITS_IS_ON(MIISR_MIDLE, &regs->MIISR))
-                       break;
+       if (vptr->vlgrp && vlan_tx_tag_present(skb)) {
+               td_ptr->tdesc1.vlan = cpu_to_le16(vlan_tx_tag_get(skb));
+               td_ptr->tdesc1.TCR |= TCR0_VETAG;
        }
 
-}
-
-/**
- *     velocity_mii_read       -       read MII data
- *     @regs: velocity registers
- *     @index: MII register index
- *     @data: buffer for received data
- *
- *     Perform a single read of an MII 16bit register. Returns zero
- *     on success or -ETIMEDOUT if the PHY did not respond.
- */
-
-static int velocity_mii_read(struct mac_regs __iomem *regs, u8 index, u16 *data)
-{
-       u16 ww;
-
        /*
-        *      Disable MIICR_MAUTO, so that mii addr can be set normally
+        *      Handle hardware checksum
         */
-       safe_disable_mii_autopoll(regs);
+       if ((vptr->flags & VELOCITY_FLAGS_TX_CSUM)
+                                && (skb->ip_summed == CHECKSUM_PARTIAL)) {
+               const struct iphdr *ip = ip_hdr(skb);
+               if (ip->protocol == IPPROTO_TCP)
+                       td_ptr->tdesc1.TCR |= TCR0_TCPCK;
+               else if (ip->protocol == IPPROTO_UDP)
+                       td_ptr->tdesc1.TCR |= (TCR0_UDPCK);
+               td_ptr->tdesc1.TCR |= TCR0_IPCK;
+       }
+       {
 
-       writeb(index, &regs->MIIADR);
+               int prev = index - 1;
 
-       BYTE_REG_BITS_ON(MIICR_RCMD, &regs->MIICR);
+               if (prev < 0)
+                       prev = vptr->options.numtx - 1;
+               td_ptr->tdesc0.len |= OWNED_BY_NIC;
+               vptr->tx.used[qnum]++;
+               vptr->tx.curr[qnum] = (index + 1) % vptr->options.numtx;
 
-       for (ww = 0; ww < W_MAX_TIMEOUT; ww++) {
-               if (!(readb(&regs->MIICR) & MIICR_RCMD))
-                       break;
+               if (AVAIL_TD(vptr, qnum) < 1)
+                       netif_stop_queue(dev);
+
+               td_ptr = &(vptr->tx.rings[qnum][prev]);
+               td_ptr->td_buf[0].size |= TD_QUEUE;
+               mac_tx_queue_wake(vptr->mac_regs, qnum);
        }
+       dev->trans_start = jiffies;
+       spin_unlock_irqrestore(&vptr->lock, flags);
+out:
+       return NETDEV_TX_OK;
+}
 
-       *data = readw(&regs->MIIDATA);
 
-       enable_mii_autopoll(regs);
-       if (ww == W_MAX_TIMEOUT)
-               return -ETIMEDOUT;
-       return 0;
-}
+static const struct net_device_ops velocity_netdev_ops = {
+       .ndo_open               = velocity_open,
+       .ndo_stop               = velocity_close,
+       .ndo_start_xmit         = velocity_xmit,
+       .ndo_get_stats          = velocity_get_stats,
+       .ndo_validate_addr      = eth_validate_addr,
+       .ndo_set_mac_address    = eth_mac_addr,
+       .ndo_set_multicast_list = velocity_set_multi,
+       .ndo_change_mtu         = velocity_change_mtu,
+       .ndo_do_ioctl           = velocity_ioctl,
+       .ndo_vlan_rx_add_vid    = velocity_vlan_rx_add_vid,
+       .ndo_vlan_rx_kill_vid   = velocity_vlan_rx_kill_vid,
+       .ndo_vlan_rx_register   = velocity_vlan_rx_register,
+};
 
 /**
- *     velocity_mii_write      -       write MII data
- *     @regs: velocity registers
- *     @index: MII register index
- *     @data: 16bit data for the MII register
+ *     velocity_init_info      -       init private data
+ *     @pdev: PCI device
+ *     @vptr: Velocity info
+ *     @info: Board type
  *
- *     Perform a single write to an MII 16bit register. Returns zero
- *     on success or -ETIMEDOUT if the PHY did not respond.
+ *     Set up the initial velocity_info struct for the device that has been
+ *     discovered.
  */
-
-static int velocity_mii_write(struct mac_regs __iomem *regs, u8 mii_addr, u16 data)
+static void __devinit velocity_init_info(struct pci_dev *pdev,
+                                        struct velocity_info *vptr,
+                                        const struct velocity_info_tbl *info)
 {
-       u16 ww;
-
-       /*
-        *      Disable MIICR_MAUTO, so that mii addr can be set normally
-        */
-       safe_disable_mii_autopoll(regs);
-
-       /* MII reg offset */
-       writeb(mii_addr, &regs->MIIADR);
-       /* set MII data */
-       writew(data, &regs->MIIDATA);
-
-       /* turn on MIICR_WCMD */
-       BYTE_REG_BITS_ON(MIICR_WCMD, &regs->MIICR);
-
-       /* W_MAX_TIMEOUT is the timeout period */
-       for (ww = 0; ww < W_MAX_TIMEOUT; ww++) {
-               udelay(5);
-               if (!(readb(&regs->MIICR) & MIICR_WCMD))
-                       break;
-       }
-       enable_mii_autopoll(regs);
+       memset(vptr, 0, sizeof(struct velocity_info));
 
-       if (ww == W_MAX_TIMEOUT)
-               return -ETIMEDOUT;
-       return 0;
+       vptr->pdev = pdev;
+       vptr->chip_id = info->chip_id;
+       vptr->tx.numq = info->txqueue;
+       vptr->multicast_limit = MCAM_SIZE;
+       spin_lock_init(&vptr->lock);
+       INIT_LIST_HEAD(&vptr->list);
 }
 
 /**
- *     velocity_get_opt_media_mode     -       get media selection
- *     @vptr: velocity adapter
+ *     velocity_get_pci_info   -       retrieve PCI info for device
+ *     @vptr: velocity device
+ *     @pdev: PCI device it matches
  *
- *     Get the media mode stored in EEPROM or module options and load
- *     mii_status accordingly. The requested link state information
- *     is also returned.
+ *     Retrieve the PCI configuration space data that interests us from
+ *     the kernel PCI layer
  */
-
-static u32 velocity_get_opt_media_mode(struct velocity_info *vptr)
+static int __devinit velocity_get_pci_info(struct velocity_info *vptr, struct pci_dev *pdev)
 {
-       u32 status = 0;
+       vptr->rev_id = pdev->revision;
 
-       switch (vptr->options.spd_dpx) {
-       case SPD_DPX_AUTO:
-               status = VELOCITY_AUTONEG_ENABLE;
-               break;
-       case SPD_DPX_100_FULL:
-               status = VELOCITY_SPEED_100 | VELOCITY_DUPLEX_FULL;
-               break;
-       case SPD_DPX_10_FULL:
-               status = VELOCITY_SPEED_10 | VELOCITY_DUPLEX_FULL;
-               break;
-       case SPD_DPX_100_HALF:
-               status = VELOCITY_SPEED_100;
-               break;
-       case SPD_DPX_10_HALF:
-               status = VELOCITY_SPEED_10;
-               break;
-       }
-       vptr->mii_status = status;
-       return status;
-}
+       pci_set_master(pdev);
 
-/**
- *     mii_set_auto_on         -       autonegotiate on
- *     @vptr: velocity
- *
- *     Enable autonegotation on this interface
- */
-
-static void mii_set_auto_on(struct velocity_info *vptr)
-{
-       if (MII_REG_BITS_IS_ON(BMCR_AUTO, MII_REG_BMCR, vptr->mac_regs))
-               MII_REG_BITS_ON(BMCR_REAUTO, MII_REG_BMCR, vptr->mac_regs);
-       else
-               MII_REG_BITS_ON(BMCR_AUTO, MII_REG_BMCR, vptr->mac_regs);
-}
-
-
-/*
-static void mii_set_auto_off(struct velocity_info * vptr)
-{
-    MII_REG_BITS_OFF(BMCR_AUTO, MII_REG_BMCR, vptr->mac_regs);
-}
-*/
-
-/**
- *     set_mii_flow_control    -       flow control setup
- *     @vptr: velocity interface
- *
- *     Set up the flow control on this interface according to
- *     the supplied user/eeprom options.
- */
-
-static void set_mii_flow_control(struct velocity_info *vptr)
-{
-       /*Enable or Disable PAUSE in ANAR */
-       switch (vptr->options.flow_cntl) {
-       case FLOW_CNTL_TX:
-               MII_REG_BITS_OFF(ANAR_PAUSE, MII_REG_ANAR, vptr->mac_regs);
-               MII_REG_BITS_ON(ANAR_ASMDIR, MII_REG_ANAR, vptr->mac_regs);
-               break;
-
-       case FLOW_CNTL_RX:
-               MII_REG_BITS_ON(ANAR_PAUSE, MII_REG_ANAR, vptr->mac_regs);
-               MII_REG_BITS_ON(ANAR_ASMDIR, MII_REG_ANAR, vptr->mac_regs);
-               break;
-
-       case FLOW_CNTL_TX_RX:
-               MII_REG_BITS_ON(ANAR_PAUSE, MII_REG_ANAR, vptr->mac_regs);
-               MII_REG_BITS_ON(ANAR_ASMDIR, MII_REG_ANAR, vptr->mac_regs);
-               break;
-
-       case FLOW_CNTL_DISABLE:
-               MII_REG_BITS_OFF(ANAR_PAUSE, MII_REG_ANAR, vptr->mac_regs);
-               MII_REG_BITS_OFF(ANAR_ASMDIR, MII_REG_ANAR, vptr->mac_regs);
-               break;
-       default:
-               break;
-       }
-}
-
-/**
- *     velocity_set_media_mode         -       set media mode
- *     @mii_status: old MII link state
- *
- *     Check the media link state and configure the flow control
- *     PHY and also velocity hardware setup accordingly. In particular
- *     we need to set up CD polling and frame bursting.
- */
-
-static int velocity_set_media_mode(struct velocity_info *vptr, u32 mii_status)
-{
-       u32 curr_status;
-       struct mac_regs __iomem * regs = vptr->mac_regs;
-
-       vptr->mii_status = mii_check_media_mode(vptr->mac_regs);
-       curr_status = vptr->mii_status & (~VELOCITY_LINK_FAIL);
-
-       /* Set mii link status */
-       set_mii_flow_control(vptr);
-
-       /*
-          Check if new status is consisent with current status
-          if (((mii_status & curr_status) & VELOCITY_AUTONEG_ENABLE)
-          || (mii_status==curr_status)) {
-          vptr->mii_status=mii_check_media_mode(vptr->mac_regs);
-          vptr->mii_status=check_connection_type(vptr->mac_regs);
-          VELOCITY_PRT(MSG_LEVEL_INFO, "Velocity link no change\n");
-          return 0;
-          }
-        */
-
-       if (PHYID_GET_PHY_ID(vptr->phy_id) == PHYID_CICADA_CS8201) {
-               MII_REG_BITS_ON(AUXCR_MDPPS, MII_REG_AUXCR, vptr->mac_regs);
-       }
-
-       /*
-        *      If connection type is AUTO
-        */
-       if (mii_status & VELOCITY_AUTONEG_ENABLE) {
-               VELOCITY_PRT(MSG_LEVEL_INFO, "Velocity is AUTO mode\n");
-               /* clear force MAC mode bit */
-               BYTE_REG_BITS_OFF(CHIPGCR_FCMODE, &regs->CHIPGCR);
-               /* set duplex mode of MAC according to duplex mode of MII */
-               MII_REG_BITS_ON(ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10, MII_REG_ANAR, vptr->mac_regs);
-               MII_REG_BITS_ON(G1000CR_1000FD | G1000CR_1000, MII_REG_G1000CR, vptr->mac_regs);
-               MII_REG_BITS_ON(BMCR_SPEED1G, MII_REG_BMCR, vptr->mac_regs);
-
-               /* enable AUTO-NEGO mode */
-               mii_set_auto_on(vptr);
-       } else {
-               u16 ANAR;
-               u8 CHIPGCR;
-
-               /*
-                * 1. if it's 3119, disable frame bursting in halfduplex mode
-                *    and enable it in fullduplex mode
-                * 2. set correct MII/GMII and half/full duplex mode in CHIPGCR
-                * 3. only enable CD heart beat counter in 10HD mode
-                */
-
-               /* set force MAC mode bit */
-               BYTE_REG_BITS_ON(CHIPGCR_FCMODE, &regs->CHIPGCR);
-
-               CHIPGCR = readb(&regs->CHIPGCR);
-               CHIPGCR &= ~CHIPGCR_FCGMII;
-
-               if (mii_status & VELOCITY_DUPLEX_FULL) {
-                       CHIPGCR |= CHIPGCR_FCFDX;
-                       writeb(CHIPGCR, &regs->CHIPGCR);
-                       VELOCITY_PRT(MSG_LEVEL_INFO, "set Velocity to forced full mode\n");
-                       if (vptr->rev_id < REV_ID_VT3216_A0)
-                               BYTE_REG_BITS_OFF(TCR_TB2BDIS, &regs->TCR);
-               } else {
-                       CHIPGCR &= ~CHIPGCR_FCFDX;
-                       VELOCITY_PRT(MSG_LEVEL_INFO, "set Velocity to forced half mode\n");
-                       writeb(CHIPGCR, &regs->CHIPGCR);
-                       if (vptr->rev_id < REV_ID_VT3216_A0)
-                               BYTE_REG_BITS_ON(TCR_TB2BDIS, &regs->TCR);
-               }
-
-               MII_REG_BITS_OFF(G1000CR_1000FD | G1000CR_1000, MII_REG_G1000CR, vptr->mac_regs);
-
-               if (!(mii_status & VELOCITY_DUPLEX_FULL) && (mii_status & VELOCITY_SPEED_10)) {
-                       BYTE_REG_BITS_OFF(TESTCFG_HBDIS, &regs->TESTCFG);
-               } else {
-                       BYTE_REG_BITS_ON(TESTCFG_HBDIS, &regs->TESTCFG);
-               }
-               /* MII_REG_BITS_OFF(BMCR_SPEED1G, MII_REG_BMCR, vptr->mac_regs); */
-               velocity_mii_read(vptr->mac_regs, MII_REG_ANAR, &ANAR);
-               ANAR &= (~(ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10));
-               if (mii_status & VELOCITY_SPEED_100) {
-                       if (mii_status & VELOCITY_DUPLEX_FULL)
-                               ANAR |= ANAR_TXFD;
-                       else
-                               ANAR |= ANAR_TX;
-               } else {
-                       if (mii_status & VELOCITY_DUPLEX_FULL)
-                               ANAR |= ANAR_10FD;
-                       else
-                               ANAR |= ANAR_10;
-               }
-               velocity_mii_write(vptr->mac_regs, MII_REG_ANAR, ANAR);
-               /* enable AUTO-NEGO mode */
-               mii_set_auto_on(vptr);
-               /* MII_REG_BITS_ON(BMCR_AUTO, MII_REG_BMCR, vptr->mac_regs); */
-       }
-       /* vptr->mii_status=mii_check_media_mode(vptr->mac_regs); */
-       /* vptr->mii_status=check_connection_type(vptr->mac_regs); */
-       return VELOCITY_LINK_CHANGE;
-}
-
-/**
- *     mii_check_media_mode    -       check media state
- *     @regs: velocity registers
- *
- *     Check the current MII status and determine the link status
- *     accordingly
- */
-
-static u32 mii_check_media_mode(struct mac_regs __iomem * regs)
-{
-       u32 status = 0;
-       u16 ANAR;
-
-       if (!MII_REG_BITS_IS_ON(BMSR_LNK, MII_REG_BMSR, regs))
-               status |= VELOCITY_LINK_FAIL;
-
-       if (MII_REG_BITS_IS_ON(G1000CR_1000FD, MII_REG_G1000CR, regs))
-               status |= VELOCITY_SPEED_1000 | VELOCITY_DUPLEX_FULL;
-       else if (MII_REG_BITS_IS_ON(G1000CR_1000, MII_REG_G1000CR, regs))
-               status |= (VELOCITY_SPEED_1000);
-       else {
-               velocity_mii_read(regs, MII_REG_ANAR, &ANAR);
-               if (ANAR & ANAR_TXFD)
-                       status |= (VELOCITY_SPEED_100 | VELOCITY_DUPLEX_FULL);
-               else if (ANAR & ANAR_TX)
-                       status |= VELOCITY_SPEED_100;
-               else if (ANAR & ANAR_10FD)
-                       status |= (VELOCITY_SPEED_10 | VELOCITY_DUPLEX_FULL);
-               else
-                       status |= (VELOCITY_SPEED_10);
-       }
-
-       if (MII_REG_BITS_IS_ON(BMCR_AUTO, MII_REG_BMCR, regs)) {
-               velocity_mii_read(regs, MII_REG_ANAR, &ANAR);
-               if ((ANAR & (ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10))
-                   == (ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10)) {
-                       if (MII_REG_BITS_IS_ON(G1000CR_1000 | G1000CR_1000FD, MII_REG_G1000CR, regs))
-                               status |= VELOCITY_AUTONEG_ENABLE;
-               }
-       }
-
-       return status;
-}
-
-static u32 check_connection_type(struct mac_regs __iomem * regs)
-{
-       u32 status = 0;
-       u8 PHYSR0;
-       u16 ANAR;
-       PHYSR0 = readb(&regs->PHYSR0);
-
-       /*
-          if (!(PHYSR0 & PHYSR0_LINKGD))
-          status|=VELOCITY_LINK_FAIL;
-        */
-
-       if (PHYSR0 & PHYSR0_FDPX)
-               status |= VELOCITY_DUPLEX_FULL;
-
-       if (PHYSR0 & PHYSR0_SPDG)
-               status |= VELOCITY_SPEED_1000;
-       else if (PHYSR0 & PHYSR0_SPD10)
-               status |= VELOCITY_SPEED_10;
-       else
-               status |= VELOCITY_SPEED_100;
-
-       if (MII_REG_BITS_IS_ON(BMCR_AUTO, MII_REG_BMCR, regs)) {
-               velocity_mii_read(regs, MII_REG_ANAR, &ANAR);
-               if ((ANAR & (ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10))
-                   == (ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10)) {
-                       if (MII_REG_BITS_IS_ON(G1000CR_1000 | G1000CR_1000FD, MII_REG_G1000CR, regs))
-                               status |= VELOCITY_AUTONEG_ENABLE;
-               }
-       }
-
-       return status;
-}
-
-/**
- *     enable_flow_control_ability     -       flow control
- *     @vptr: veloity to configure
- *
- *     Set up flow control according to the flow control options
- *     determined by the eeprom/configuration.
- */
-
-static void enable_flow_control_ability(struct velocity_info *vptr)
-{
-
-       struct mac_regs __iomem * regs = vptr->mac_regs;
-
-       switch (vptr->options.flow_cntl) {
-
-       case FLOW_CNTL_DEFAULT:
-               if (BYTE_REG_BITS_IS_ON(PHYSR0_RXFLC, &regs->PHYSR0))
-                       writel(CR0_FDXRFCEN, &regs->CR0Set);
-               else
-                       writel(CR0_FDXRFCEN, &regs->CR0Clr);
-
-               if (BYTE_REG_BITS_IS_ON(PHYSR0_TXFLC, &regs->PHYSR0))
-                       writel(CR0_FDXTFCEN, &regs->CR0Set);
-               else
-                       writel(CR0_FDXTFCEN, &regs->CR0Clr);
-               break;
-
-       case FLOW_CNTL_TX:
-               writel(CR0_FDXTFCEN, &regs->CR0Set);
-               writel(CR0_FDXRFCEN, &regs->CR0Clr);
-               break;
-
-       case FLOW_CNTL_RX:
-               writel(CR0_FDXRFCEN, &regs->CR0Set);
-               writel(CR0_FDXTFCEN, &regs->CR0Clr);
-               break;
-
-       case FLOW_CNTL_TX_RX:
-               writel(CR0_FDXTFCEN, &regs->CR0Set);
-               writel(CR0_FDXRFCEN, &regs->CR0Set);
-               break;
-
-       case FLOW_CNTL_DISABLE:
-               writel(CR0_FDXRFCEN, &regs->CR0Clr);
-               writel(CR0_FDXTFCEN, &regs->CR0Clr);
-               break;
+       vptr->ioaddr = pci_resource_start(pdev, 0);
+       vptr->memaddr = pci_resource_start(pdev, 1);
 
-       default:
-               break;
+       if (!(pci_resource_flags(pdev, 0) & IORESOURCE_IO)) {
+               dev_err(&pdev->dev,
+                          "region #0 is not an I/O resource, aborting.\n");
+               return -EINVAL;
        }
 
-}
-
-
-/**
- *     velocity_ethtool_up     -       pre hook for ethtool
- *     @dev: network device
- *
- *     Called before an ethtool operation. We need to make sure the
- *     chip is out of D3 state before we poke at it.
- */
-
-static int velocity_ethtool_up(struct net_device *dev)
-{
-       struct velocity_info *vptr = netdev_priv(dev);
-       if (!netif_running(dev))
-               pci_set_power_state(vptr->pdev, PCI_D0);
-       return 0;
-}
-
-/**
- *     velocity_ethtool_down   -       post hook for ethtool
- *     @dev: network device
- *
- *     Called after an ethtool operation. Restore the chip back to D3
- *     state if it isn't running.
- */
-
-static void velocity_ethtool_down(struct net_device *dev)
-{
-       struct velocity_info *vptr = netdev_priv(dev);
-       if (!netif_running(dev))
-               pci_set_power_state(vptr->pdev, PCI_D3hot);
-}
-
-static int velocity_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
-{
-       struct velocity_info *vptr = netdev_priv(dev);
-       struct mac_regs __iomem * regs = vptr->mac_regs;
-       u32 status;
-       status = check_connection_type(vptr->mac_regs);
-
-       cmd->supported = SUPPORTED_TP |
-                       SUPPORTED_Autoneg |
-                       SUPPORTED_10baseT_Half |
-                       SUPPORTED_10baseT_Full |
-                       SUPPORTED_100baseT_Half |
-                       SUPPORTED_100baseT_Full |
-                       SUPPORTED_1000baseT_Half |
-                       SUPPORTED_1000baseT_Full;
-       if (status & VELOCITY_SPEED_1000)
-               cmd->speed = SPEED_1000;
-       else if (status & VELOCITY_SPEED_100)
-               cmd->speed = SPEED_100;
-       else
-               cmd->speed = SPEED_10;
-       cmd->autoneg = (status & VELOCITY_AUTONEG_ENABLE) ? AUTONEG_ENABLE : AUTONEG_DISABLE;
-       cmd->port = PORT_TP;
-       cmd->transceiver = XCVR_INTERNAL;
-       cmd->phy_address = readb(&regs->MIIADR) & 0x1F;
-
-       if (status & VELOCITY_DUPLEX_FULL)
-               cmd->duplex = DUPLEX_FULL;
-       else
-               cmd->duplex = DUPLEX_HALF;
-
-       return 0;
-}
-
-static int velocity_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
-{
-       struct velocity_info *vptr = netdev_priv(dev);
-       u32 curr_status;
-       u32 new_status = 0;
-       int ret = 0;
-
-       curr_status = check_connection_type(vptr->mac_regs);
-       curr_status &= (~VELOCITY_LINK_FAIL);
-
-       new_status |= ((cmd->autoneg) ? VELOCITY_AUTONEG_ENABLE : 0);
-       new_status |= ((cmd->speed == SPEED_100) ? VELOCITY_SPEED_100 : 0);
-       new_status |= ((cmd->speed == SPEED_10) ? VELOCITY_SPEED_10 : 0);
-       new_status |= ((cmd->duplex == DUPLEX_FULL) ? VELOCITY_DUPLEX_FULL : 0);
-
-       if ((new_status & VELOCITY_AUTONEG_ENABLE) && (new_status != (curr_status | VELOCITY_AUTONEG_ENABLE)))
-               ret = -EINVAL;
-       else
-               velocity_set_media_mode(vptr, new_status);
-
-       return ret;
-}
-
-static u32 velocity_get_link(struct net_device *dev)
-{
-       struct velocity_info *vptr = netdev_priv(dev);
-       struct mac_regs __iomem * regs = vptr->mac_regs;
-       return BYTE_REG_BITS_IS_ON(PHYSR0_LINKGD, &regs->PHYSR0) ? 1 : 0;
-}
-
-static void velocity_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
-{
-       struct velocity_info *vptr = netdev_priv(dev);
-       strcpy(info->driver, VELOCITY_NAME);
-       strcpy(info->version, VELOCITY_VERSION);
-       strcpy(info->bus_info, pci_name(vptr->pdev));
-}
-
-static void velocity_ethtool_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
-{
-       struct velocity_info *vptr = netdev_priv(dev);
-       wol->supported = WAKE_PHY | WAKE_MAGIC | WAKE_UCAST | WAKE_ARP;
-       wol->wolopts |= WAKE_MAGIC;
-       /*
-          if (vptr->wol_opts & VELOCITY_WOL_PHY)
-                  wol.wolopts|=WAKE_PHY;
-                        */
-       if (vptr->wol_opts & VELOCITY_WOL_UCAST)
-               wol->wolopts |= WAKE_UCAST;
-       if (vptr->wol_opts & VELOCITY_WOL_ARP)
-               wol->wolopts |= WAKE_ARP;
-       memcpy(&wol->sopass, vptr->wol_passwd, 6);
-}
-
-static int velocity_ethtool_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
-{
-       struct velocity_info *vptr = netdev_priv(dev);
-
-       if (!(wol->wolopts & (WAKE_PHY | WAKE_MAGIC | WAKE_UCAST | WAKE_ARP)))
-               return -EFAULT;
-       vptr->wol_opts = VELOCITY_WOL_MAGIC;
-
-       /*
-          if (wol.wolopts & WAKE_PHY) {
-          vptr->wol_opts|=VELOCITY_WOL_PHY;
-          vptr->flags |=VELOCITY_FLAGS_WOL_ENABLED;
-          }
-        */
-
-       if (wol->wolopts & WAKE_MAGIC) {
-               vptr->wol_opts |= VELOCITY_WOL_MAGIC;
-               vptr->flags |= VELOCITY_FLAGS_WOL_ENABLED;
-       }
-       if (wol->wolopts & WAKE_UCAST) {
-               vptr->wol_opts |= VELOCITY_WOL_UCAST;
-               vptr->flags |= VELOCITY_FLAGS_WOL_ENABLED;
-       }
-       if (wol->wolopts & WAKE_ARP) {
-               vptr->wol_opts |= VELOCITY_WOL_ARP;
-               vptr->flags |= VELOCITY_FLAGS_WOL_ENABLED;
+       if ((pci_resource_flags(pdev, 1) & IORESOURCE_IO)) {
+               dev_err(&pdev->dev,
+                          "region #1 is an I/O resource, aborting.\n");
+               return -EINVAL;
        }
-       memcpy(vptr->wol_passwd, wol->sopass, 6);
-       return 0;
-}
-
-static u32 velocity_get_msglevel(struct net_device *dev)
-{
-       return msglevel;
-}
-
-static void velocity_set_msglevel(struct net_device *dev, u32 value)
-{
-        msglevel = value;
-}
-
-static const struct ethtool_ops velocity_ethtool_ops = {
-       .get_settings   =       velocity_get_settings,
-       .set_settings   =       velocity_set_settings,
-       .get_drvinfo    =       velocity_get_drvinfo,
-       .get_wol        =       velocity_ethtool_get_wol,
-       .set_wol        =       velocity_ethtool_set_wol,
-       .get_msglevel   =       velocity_get_msglevel,
-       .set_msglevel   =       velocity_set_msglevel,
-       .get_link       =       velocity_get_link,
-       .begin          =       velocity_ethtool_up,
-       .complete       =       velocity_ethtool_down
-};
 
-/**
- *     velocity_mii_ioctl              -       MII ioctl handler
- *     @dev: network device
- *     @ifr: the ifreq block for the ioctl
- *     @cmd: the command
- *
- *     Process MII requests made via ioctl from the network layer. These
- *     are used by tools like kudzu to interrogate the link state of the
- *     hardware
- */
-
-static int velocity_mii_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
-{
-       struct velocity_info *vptr = netdev_priv(dev);
-       struct mac_regs __iomem * regs = vptr->mac_regs;
-       unsigned long flags;
-       struct mii_ioctl_data *miidata = if_mii(ifr);
-       int err;
-
-       switch (cmd) {
-       case SIOCGMIIPHY:
-               miidata->phy_id = readb(&regs->MIIADR) & 0x1f;
-               break;
-       case SIOCGMIIREG:
-               if (!capable(CAP_NET_ADMIN))
-                       return -EPERM;
-               if(velocity_mii_read(vptr->mac_regs, miidata->reg_num & 0x1f, &(miidata->val_out)) < 0)
-                       return -ETIMEDOUT;
-               break;
-       case SIOCSMIIREG:
-               if (!capable(CAP_NET_ADMIN))
-                       return -EPERM;
-               spin_lock_irqsave(&vptr->lock, flags);
-               err = velocity_mii_write(vptr->mac_regs, miidata->reg_num & 0x1f, miidata->val_in);
-               spin_unlock_irqrestore(&vptr->lock, flags);
-               check_connection_type(vptr->mac_regs);
-               if(err)
-                       return err;
-               break;
-       default:
-               return -EOPNOTSUPP;
+       if (pci_resource_len(pdev, 1) < VELOCITY_IO_SIZE) {
+               dev_err(&pdev->dev, "region #1 is too small.\n");
+               return -EINVAL;
        }
+       vptr->pdev = pdev;
+
        return 0;
 }
 
-#ifdef CONFIG_PM
-
 /**
- *     velocity_save_context   -       save registers
+ *     velocity_print_info     -       per driver data
  *     @vptr: velocity
- *     @context: buffer for stored context
  *
- *     Retrieve the current configuration from the velocity hardware
- *     and stash it in the context structure, for use by the context
- *     restore functions. This allows us to save things we need across
- *     power down states
+ *     Print per driver data as the kernel driver finds Velocity
+ *     hardware
  */
-
-static void velocity_save_context(struct velocity_info *vptr, struct velocity_context * context)
+static void __devinit velocity_print_info(struct velocity_info *vptr)
 {
-       struct mac_regs __iomem * regs = vptr->mac_regs;
-       u16 i;
-       u8 __iomem *ptr = (u8 __iomem *)regs;
-
-       for (i = MAC_REG_PAR; i < MAC_REG_CR0_CLR; i += 4)
-               *((u32 *) (context->mac_reg + i)) = readl(ptr + i);
-
-       for (i = MAC_REG_MAR; i < MAC_REG_TDCSR_CLR; i += 4)
-               *((u32 *) (context->mac_reg + i)) = readl(ptr + i);
+       struct net_device *dev = vptr->dev;
 
-       for (i = MAC_REG_RDBASE_LO; i < MAC_REG_FIFO_TEST0; i += 4)
-               *((u32 *) (context->mac_reg + i)) = readl(ptr + i);
+       printk(KERN_INFO "%s: %s\n", dev->name, get_chip_name(vptr->chip_id));
+       printk(KERN_INFO "%s: Ethernet Address: %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X\n",
+               dev->name,
+               dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
+               dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
+}
 
+static u32 velocity_get_link(struct net_device *dev)
+{
+       struct velocity_info *vptr = netdev_priv(dev);
+       struct mac_regs __iomem *regs = vptr->mac_regs;
+       return BYTE_REG_BITS_IS_ON(PHYSR0_LINKGD, &regs->PHYSR0) ? 1 : 0;
 }
 
+
 /**
- *     velocity_restore_context        -       restore registers
- *     @vptr: velocity
- *     @context: buffer for stored context
+ *     velocity_found1         -       set up discovered velocity card
+ *     @pdev: PCI device
+ *     @ent: PCI device table entry that matched
  *
- *     Reload the register configuration from the velocity context
- *     created by velocity_save_context.
+ *     Configure a discovered adapter from scratch. Return a negative
+ *     errno error code on failure paths.
  */
-
-static void velocity_restore_context(struct velocity_info *vptr, struct velocity_context *context)
+static int __devinit velocity_found1(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
-       struct mac_regs __iomem * regs = vptr->mac_regs;
+       static int first = 1;
+       struct net_device *dev;
        int i;
-       u8 __iomem *ptr = (u8 __iomem *)regs;
+       const char *drv_string;
+       const struct velocity_info_tbl *info = &chip_info_table[ent->driver_data];
+       struct velocity_info *vptr;
+       struct mac_regs __iomem *regs;
+       int ret = -ENOMEM;
 
-       for (i = MAC_REG_PAR; i < MAC_REG_CR0_SET; i += 4) {
-               writel(*((u32 *) (context->mac_reg + i)), ptr + i);
+       /* FIXME: this driver, like almost all other ethernet drivers,
+        * can support more than MAX_UNITS.
+        */
+       if (velocity_nics >= MAX_UNITS) {
+               dev_notice(&pdev->dev, "already found %d NICs.\n",
+                          velocity_nics);
+               return -ENODEV;
        }
 
-       /* Just skip cr0 */
-       for (i = MAC_REG_CR1_SET; i < MAC_REG_CR0_CLR; i++) {
-               /* Clear */
-               writeb(~(*((u8 *) (context->mac_reg + i))), ptr + i + 4);
-               /* Set */
-               writeb(*((u8 *) (context->mac_reg + i)), ptr + i);
+       dev = alloc_etherdev(sizeof(struct velocity_info));
+       if (!dev) {
+               dev_err(&pdev->dev, "allocate net device failed.\n");
+               goto out;
        }
 
-       for (i = MAC_REG_MAR; i < MAC_REG_IMR; i += 4) {
-               writel(*((u32 *) (context->mac_reg + i)), ptr + i);
+       /* Chain it all together */
+
+       SET_NETDEV_DEV(dev, &pdev->dev);
+       vptr = netdev_priv(dev);
+
+
+       if (first) {
+               printk(KERN_INFO "%s Ver. %s\n",
+                       VELOCITY_FULL_DRV_NAM, VELOCITY_VERSION);
+               printk(KERN_INFO "Copyright (c) 2002, 2003 VIA Networking Technologies, Inc.\n");
+               printk(KERN_INFO "Copyright (c) 2004 Red Hat Inc.\n");
+               first = 0;
        }
 
-       for (i = MAC_REG_RDBASE_LO; i < MAC_REG_FIFO_TEST0; i += 4) {
-               writel(*((u32 *) (context->mac_reg + i)), ptr + i);
+       velocity_init_info(pdev, vptr, info);
+
+       vptr->dev = dev;
+
+       dev->irq = pdev->irq;
+
+       ret = pci_enable_device(pdev);
+       if (ret < 0)
+               goto err_free_dev;
+
+       ret = velocity_get_pci_info(vptr, pdev);
+       if (ret < 0) {
+               /* error message already printed */
+               goto err_disable;
        }
 
-       for (i = MAC_REG_TDCSR_SET; i <= MAC_REG_RDCSR_SET; i++) {
-               writeb(*((u8 *) (context->mac_reg + i)), ptr + i);
+       ret = pci_request_regions(pdev, VELOCITY_NAME);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "No PCI resources.\n");
+               goto err_disable;
+       }
+
+       regs = ioremap(vptr->memaddr, VELOCITY_IO_SIZE);
+       if (regs == NULL) {
+               ret = -EIO;
+               goto err_release_res;
+       }
+
+       vptr->mac_regs = regs;
+
+       mac_wol_reset(regs);
+
+       dev->base_addr = vptr->ioaddr;
+
+       for (i = 0; i < 6; i++)
+               dev->dev_addr[i] = readb(&regs->PAR[i]);
+
+
+       drv_string = dev_driver_string(&pdev->dev);
+
+       velocity_get_options(&vptr->options, velocity_nics, drv_string);
+
+       /*
+        *      Mask out the options cannot be set to the chip
+        */
+
+       vptr->options.flags &= info->flags;
+
+       /*
+        *      Enable the chip specified capbilities
+        */
+
+       vptr->flags = vptr->options.flags | (info->flags & 0xFF000000UL);
+
+       vptr->wol_opts = vptr->options.wol_opts;
+       vptr->flags |= VELOCITY_FLAGS_WOL_ENABLED;
+
+       vptr->phy_id = MII_GET_PHY_ID(vptr->mac_regs);
+
+       dev->irq = pdev->irq;
+       dev->netdev_ops = &velocity_netdev_ops;
+       dev->ethtool_ops = &velocity_ethtool_ops;
+
+       dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_FILTER |
+               NETIF_F_HW_VLAN_RX;
+
+       if (vptr->flags & VELOCITY_FLAGS_TX_CSUM)
+               dev->features |= NETIF_F_IP_CSUM;
+
+       ret = register_netdev(dev);
+       if (ret < 0)
+               goto err_iounmap;
+
+       if (!velocity_get_link(dev)) {
+               netif_carrier_off(dev);
+               vptr->mii_status |= VELOCITY_LINK_FAIL;
+       }
+
+       velocity_print_info(vptr);
+       pci_set_drvdata(pdev, dev);
+
+       /* and leave the chip powered down */
+
+       pci_set_power_state(pdev, PCI_D3hot);
+#ifdef CONFIG_PM
+       {
+               unsigned long flags;
+
+               spin_lock_irqsave(&velocity_dev_list_lock, flags);
+               list_add(&vptr->list, &velocity_dev_list);
+               spin_unlock_irqrestore(&velocity_dev_list_lock, flags);
        }
+#endif
+       velocity_nics++;
+out:
+       return ret;
 
+err_iounmap:
+       iounmap(regs);
+err_release_res:
+       pci_release_regions(pdev);
+err_disable:
+       pci_disable_device(pdev);
+err_free_dev:
+       free_netdev(dev);
+       goto out;
 }
 
+
+#ifdef CONFIG_PM
 /**
  *     wol_calc_crc            -       WOL CRC
  *     @pattern: data pattern
@@ -3281,8 +2814,7 @@ static void velocity_restore_context(struct velocity_info *vptr, struct velocity
  *     Compute the wake on lan crc hashes for the packet header
  *     we are interested in.
  */
-
-static u16 wol_calc_crc(int size, u8 * pattern, u8 *mask_pattern)
+static u16 wol_calc_crc(int size, u8 *pattern, u8 *mask_pattern)
 {
        u16 crc = 0xFFFF;
        u8 mask;
@@ -3318,10 +2850,9 @@ static u16 wol_calc_crc(int size, u8 * pattern, u8 *mask_pattern)
  *
  *     FIXME: check static buffer is safe here
  */
-
 static int velocity_set_wol(struct velocity_info *vptr)
 {
-       struct mac_regs __iomem * regs = vptr->mac_regs;
+       struct mac_regs __iomem *regs = vptr->mac_regs;
        static u8 buf[256];
        int i;
 
@@ -3339,9 +2870,8 @@ static int velocity_set_wol(struct velocity_info *vptr)
           writew((WOLCR_LINKON_EN|WOLCR_LINKOFF_EN), &regs->WOLCRSet);
         */
 
-       if (vptr->wol_opts & VELOCITY_WOL_UCAST) {
+       if (vptr->wol_opts & VELOCITY_WOL_UCAST)
                writew(WOLCR_UNICAST_EN, &regs->WOLCRSet);
-       }
 
        if (vptr->wol_opts & VELOCITY_WOL_ARP) {
                struct arp_packet *arp = (struct arp_packet *) buf;
@@ -3396,13 +2926,40 @@ static int velocity_set_wol(struct velocity_info *vptr)
        return 0;
 }
 
+/**
+ *     velocity_save_context   -       save registers
+ *     @vptr: velocity
+ *     @context: buffer for stored context
+ *
+ *     Retrieve the current configuration from the velocity hardware
+ *     and stash it in the context structure, for use by the context
+ *     restore functions. This allows us to save things we need across
+ *     power down states
+ */
+static void velocity_save_context(struct velocity_info *vptr, struct velocity_context *context)
+{
+       struct mac_regs __iomem *regs = vptr->mac_regs;
+       u16 i;
+       u8 __iomem *ptr = (u8 __iomem *)regs;
+
+       for (i = MAC_REG_PAR; i < MAC_REG_CR0_CLR; i += 4)
+               *((u32 *) (context->mac_reg + i)) = readl(ptr + i);
+
+       for (i = MAC_REG_MAR; i < MAC_REG_TDCSR_CLR; i += 4)
+               *((u32 *) (context->mac_reg + i)) = readl(ptr + i);
+
+       for (i = MAC_REG_RDBASE_LO; i < MAC_REG_FIFO_TEST0; i += 4)
+               *((u32 *) (context->mac_reg + i)) = readl(ptr + i);
+
+}
+
 static int velocity_suspend(struct pci_dev *pdev, pm_message_t state)
 {
        struct net_device *dev = pci_get_drvdata(pdev);
        struct velocity_info *vptr = netdev_priv(dev);
        unsigned long flags;
 
-       if(!netif_running(vptr->dev))
+       if (!netif_running(vptr->dev))
                return 0;
 
        netif_device_detach(vptr->dev);
@@ -3423,11 +2980,46 @@ static int velocity_suspend(struct pci_dev *pdev, pm_message_t state)
                pci_disable_device(pdev);
                pci_set_power_state(pdev, pci_choose_state(pdev, state));
        }
-#else
-       pci_set_power_state(pdev, pci_choose_state(pdev, state));
-#endif
-       spin_unlock_irqrestore(&vptr->lock, flags);
-       return 0;
+#else
+       pci_set_power_state(pdev, pci_choose_state(pdev, state));
+#endif
+       spin_unlock_irqrestore(&vptr->lock, flags);
+       return 0;
+}
+
+/**
+ *     velocity_restore_context        -       restore registers
+ *     @vptr: velocity
+ *     @context: buffer for stored context
+ *
+ *     Reload the register configuration from the velocity context
+ *     created by velocity_save_context.
+ */
+static void velocity_restore_context(struct velocity_info *vptr, struct velocity_context *context)
+{
+       struct mac_regs __iomem *regs = vptr->mac_regs;
+       int i;
+       u8 __iomem *ptr = (u8 __iomem *)regs;
+
+       for (i = MAC_REG_PAR; i < MAC_REG_CR0_SET; i += 4)
+               writel(*((u32 *) (context->mac_reg + i)), ptr + i);
+
+       /* Just skip cr0 */
+       for (i = MAC_REG_CR1_SET; i < MAC_REG_CR0_CLR; i++) {
+               /* Clear */
+               writeb(~(*((u8 *) (context->mac_reg + i))), ptr + i + 4);
+               /* Set */
+               writeb(*((u8 *) (context->mac_reg + i)), ptr + i);
+       }
+
+       for (i = MAC_REG_MAR; i < MAC_REG_IMR; i += 4)
+               writel(*((u32 *) (context->mac_reg + i)), ptr + i);
+
+       for (i = MAC_REG_RDBASE_LO; i < MAC_REG_FIFO_TEST0; i += 4)
+               writel(*((u32 *) (context->mac_reg + i)), ptr + i);
+
+       for (i = MAC_REG_TDCSR_SET; i <= MAC_REG_RDCSR_SET; i++)
+               writeb(*((u8 *) (context->mac_reg + i)), ptr + i);
 }
 
 static int velocity_resume(struct pci_dev *pdev)
@@ -3437,7 +3029,7 @@ static int velocity_resume(struct pci_dev *pdev)
        unsigned long flags;
        int i;
 
-       if(!netif_running(vptr->dev))
+       if (!netif_running(vptr->dev))
                return 0;
 
        pci_set_power_state(pdev, PCI_D0);
@@ -3454,9 +3046,8 @@ static int velocity_resume(struct pci_dev *pdev)
        velocity_tx_srv(vptr, 0);
 
        for (i = 0; i < vptr->tx.numq; i++) {
-               if (vptr->tx.used[i]) {
+               if (vptr->tx.used[i])
                        mac_tx_queue_wake(vptr->mac_regs, i);
-               }
        }
 
        mac_enable_int(vptr->mac_regs);
@@ -3465,9 +3056,190 @@ static int velocity_resume(struct pci_dev *pdev)
 
        return 0;
 }
+#endif
 
-#ifdef CONFIG_INET
+/*
+ *     Definition for our device driver. The PCI layer interface
+ *     uses this to handle all our card discover and plugging
+ */
+static struct pci_driver velocity_driver = {
+      .name    = VELOCITY_NAME,
+      .id_table        = velocity_id_table,
+      .probe   = velocity_found1,
+      .remove  = __devexit_p(velocity_remove1),
+#ifdef CONFIG_PM
+      .suspend = velocity_suspend,
+      .resume  = velocity_resume,
+#endif
+};
+
+
+/**
+ *     velocity_ethtool_up     -       pre hook for ethtool
+ *     @dev: network device
+ *
+ *     Called before an ethtool operation. We need to make sure the
+ *     chip is out of D3 state before we poke at it.
+ */
+static int velocity_ethtool_up(struct net_device *dev)
+{
+       struct velocity_info *vptr = netdev_priv(dev);
+       if (!netif_running(dev))
+               pci_set_power_state(vptr->pdev, PCI_D0);
+       return 0;
+}
+
+/**
+ *     velocity_ethtool_down   -       post hook for ethtool
+ *     @dev: network device
+ *
+ *     Called after an ethtool operation. Restore the chip back to D3
+ *     state if it isn't running.
+ */
+static void velocity_ethtool_down(struct net_device *dev)
+{
+       struct velocity_info *vptr = netdev_priv(dev);
+       if (!netif_running(dev))
+               pci_set_power_state(vptr->pdev, PCI_D3hot);
+}
+
+static int velocity_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+       struct velocity_info *vptr = netdev_priv(dev);
+       struct mac_regs __iomem *regs = vptr->mac_regs;
+       u32 status;
+       status = check_connection_type(vptr->mac_regs);
+
+       cmd->supported = SUPPORTED_TP |
+                       SUPPORTED_Autoneg |
+                       SUPPORTED_10baseT_Half |
+                       SUPPORTED_10baseT_Full |
+                       SUPPORTED_100baseT_Half |
+                       SUPPORTED_100baseT_Full |
+                       SUPPORTED_1000baseT_Half |
+                       SUPPORTED_1000baseT_Full;
+       if (status & VELOCITY_SPEED_1000)
+               cmd->speed = SPEED_1000;
+       else if (status & VELOCITY_SPEED_100)
+               cmd->speed = SPEED_100;
+       else
+               cmd->speed = SPEED_10;
+       cmd->autoneg = (status & VELOCITY_AUTONEG_ENABLE) ? AUTONEG_ENABLE : AUTONEG_DISABLE;
+       cmd->port = PORT_TP;
+       cmd->transceiver = XCVR_INTERNAL;
+       cmd->phy_address = readb(&regs->MIIADR) & 0x1F;
+
+       if (status & VELOCITY_DUPLEX_FULL)
+               cmd->duplex = DUPLEX_FULL;
+       else
+               cmd->duplex = DUPLEX_HALF;
+
+       return 0;
+}
+
+static int velocity_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+       struct velocity_info *vptr = netdev_priv(dev);
+       u32 curr_status;
+       u32 new_status = 0;
+       int ret = 0;
+
+       curr_status = check_connection_type(vptr->mac_regs);
+       curr_status &= (~VELOCITY_LINK_FAIL);
+
+       new_status |= ((cmd->autoneg) ? VELOCITY_AUTONEG_ENABLE : 0);
+       new_status |= ((cmd->speed == SPEED_100) ? VELOCITY_SPEED_100 : 0);
+       new_status |= ((cmd->speed == SPEED_10) ? VELOCITY_SPEED_10 : 0);
+       new_status |= ((cmd->duplex == DUPLEX_FULL) ? VELOCITY_DUPLEX_FULL : 0);
+
+       if ((new_status & VELOCITY_AUTONEG_ENABLE) && (new_status != (curr_status | VELOCITY_AUTONEG_ENABLE)))
+               ret = -EINVAL;
+       else
+               velocity_set_media_mode(vptr, new_status);
+
+       return ret;
+}
+
+static void velocity_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
+{
+       struct velocity_info *vptr = netdev_priv(dev);
+       strcpy(info->driver, VELOCITY_NAME);
+       strcpy(info->version, VELOCITY_VERSION);
+       strcpy(info->bus_info, pci_name(vptr->pdev));
+}
+
+static void velocity_ethtool_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
+{
+       struct velocity_info *vptr = netdev_priv(dev);
+       wol->supported = WAKE_PHY | WAKE_MAGIC | WAKE_UCAST | WAKE_ARP;
+       wol->wolopts |= WAKE_MAGIC;
+       /*
+          if (vptr->wol_opts & VELOCITY_WOL_PHY)
+                  wol.wolopts|=WAKE_PHY;
+                        */
+       if (vptr->wol_opts & VELOCITY_WOL_UCAST)
+               wol->wolopts |= WAKE_UCAST;
+       if (vptr->wol_opts & VELOCITY_WOL_ARP)
+               wol->wolopts |= WAKE_ARP;
+       memcpy(&wol->sopass, vptr->wol_passwd, 6);
+}
+
+static int velocity_ethtool_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
+{
+       struct velocity_info *vptr = netdev_priv(dev);
+
+       if (!(wol->wolopts & (WAKE_PHY | WAKE_MAGIC | WAKE_UCAST | WAKE_ARP)))
+               return -EFAULT;
+       vptr->wol_opts = VELOCITY_WOL_MAGIC;
+
+       /*
+          if (wol.wolopts & WAKE_PHY) {
+          vptr->wol_opts|=VELOCITY_WOL_PHY;
+          vptr->flags |=VELOCITY_FLAGS_WOL_ENABLED;
+          }
+        */
+
+       if (wol->wolopts & WAKE_MAGIC) {
+               vptr->wol_opts |= VELOCITY_WOL_MAGIC;
+               vptr->flags |= VELOCITY_FLAGS_WOL_ENABLED;
+       }
+       if (wol->wolopts & WAKE_UCAST) {
+               vptr->wol_opts |= VELOCITY_WOL_UCAST;
+               vptr->flags |= VELOCITY_FLAGS_WOL_ENABLED;
+       }
+       if (wol->wolopts & WAKE_ARP) {
+               vptr->wol_opts |= VELOCITY_WOL_ARP;
+               vptr->flags |= VELOCITY_FLAGS_WOL_ENABLED;
+       }
+       memcpy(vptr->wol_passwd, wol->sopass, 6);
+       return 0;
+}
+
+static u32 velocity_get_msglevel(struct net_device *dev)
+{
+       return msglevel;
+}
+
+static void velocity_set_msglevel(struct net_device *dev, u32 value)
+{
+        msglevel = value;
+}
+
+static const struct ethtool_ops velocity_ethtool_ops = {
+       .get_settings   =       velocity_get_settings,
+       .set_settings   =       velocity_set_settings,
+       .get_drvinfo    =       velocity_get_drvinfo,
+       .get_wol        =       velocity_ethtool_get_wol,
+       .set_wol        =       velocity_ethtool_set_wol,
+       .get_msglevel   =       velocity_get_msglevel,
+       .set_msglevel   =       velocity_set_msglevel,
+       .get_link       =       velocity_get_link,
+       .begin          =       velocity_ethtool_up,
+       .complete       =       velocity_ethtool_down
+};
 
+#ifdef CONFIG_PM
+#ifdef CONFIG_INET
 static int velocity_netdev_event(struct notifier_block *nb, unsigned long notification, void *ptr)
 {
        struct in_ifaddr *ifa = (struct in_ifaddr *) ptr;
@@ -3489,6 +3261,63 @@ static int velocity_netdev_event(struct notifier_block *nb, unsigned long notifi
 
        return NOTIFY_DONE;
 }
+#endif /* CONFIG_INET */
+#endif /* CONFIG_PM */
 
-#endif
-#endif
+#if defined(CONFIG_PM) && defined(CONFIG_INET)
+static struct notifier_block velocity_inetaddr_notifier = {
+      .notifier_call   = velocity_netdev_event,
+};
+
+static void velocity_register_notifier(void)
+{
+       register_inetaddr_notifier(&velocity_inetaddr_notifier);
+}
+
+static void velocity_unregister_notifier(void)
+{
+       unregister_inetaddr_notifier(&velocity_inetaddr_notifier);
+}
+
+#else
+
+#define velocity_register_notifier()   do {} while (0)
+#define velocity_unregister_notifier() do {} while (0)
+
+#endif /* defined(CONFIG_PM) && defined(CONFIG_INET) */
+
+/**
+ *     velocity_init_module    -       load time function
+ *
+ *     Called when the velocity module is loaded. The PCI driver
+ *     is registered with the PCI layer, and in turn will call
+ *     the probe functions for each velocity adapter installed
+ *     in the system.
+ */
+static int __init velocity_init_module(void)
+{
+       int ret;
+
+       velocity_register_notifier();
+       ret = pci_register_driver(&velocity_driver);
+       if (ret < 0)
+               velocity_unregister_notifier();
+       return ret;
+}
+
+/**
+ *     velocity_cleanup        -       module unload
+ *
+ *     When the velocity hardware is unloaded this function is called.
+ *     It will clean up the notifiers and the unregister the PCI
+ *     driver interface for this hardware. This in turn cleans up
+ *     all discovered interfaces before returning from the function
+ */
+static void __exit velocity_cleanup_module(void)
+{
+       velocity_unregister_notifier();
+       pci_unregister_driver(&velocity_driver);
+}
+
+module_init(velocity_init_module);
+module_exit(velocity_cleanup_module);
index 4cd3f6c..2f00c13 100644 (file)
@@ -96,8 +96,8 @@
  * Bits in the CSM register
  */
 
-#define CSM_IPOK            0x40       //IP Checkusm validatiaon ok
-#define CSM_TUPOK           0x20       //TCP/UDP Checkusm validatiaon ok
+#define CSM_IPOK            0x40       //IP Checksum validation ok
+#define CSM_TUPOK           0x20       //TCP/UDP Checksum validation ok
 #define CSM_FRAG            0x10       //Fragment IP datagram
 #define CSM_IPKT            0x04       //Received an IP packet
 #define CSM_TCPKT           0x02       //Received a TCP packet
@@ -819,7 +819,7 @@ enum  velocity_owner {
  *     Bits in the EECSR register
  */
 
-#define EECSR_EMBP          0x40       /* eeprom embeded programming */
+#define EECSR_EMBP          0x40       /* eeprom embedded programming */
 #define EECSR_RELOAD        0x20       /* eeprom content reload */
 #define EECSR_DPM           0x10       /* eeprom direct programming */
 #define EECSR_ECS           0x08       /* eeprom CS pin */
index 2a6e81d..a6f903f 100644 (file)
@@ -774,6 +774,7 @@ static struct ethtool_ops virtnet_ethtool_ops = {
        .set_tx_csum = virtnet_set_tx_csum,
        .set_sg = ethtool_op_set_sg,
        .set_tso = ethtool_op_set_tso,
+       .set_ufo = ethtool_op_set_ufo,
        .get_link = ethtool_op_get_link,
 };
 
@@ -1005,7 +1006,7 @@ static unsigned int features[] = {
        VIRTIO_NET_F_GSO, VIRTIO_NET_F_MAC,
        VIRTIO_NET_F_HOST_TSO4, VIRTIO_NET_F_HOST_UFO, VIRTIO_NET_F_HOST_TSO6,
        VIRTIO_NET_F_HOST_ECN, VIRTIO_NET_F_GUEST_TSO4, VIRTIO_NET_F_GUEST_TSO6,
-       VIRTIO_NET_F_GUEST_ECN, /* We don't yet handle UFO input. */
+       VIRTIO_NET_F_GUEST_ECN, VIRTIO_NET_F_GUEST_UFO,
        VIRTIO_NET_F_MRG_RXBUF, VIRTIO_NET_F_STATUS, VIRTIO_NET_F_CTRL_VQ,
        VIRTIO_NET_F_CTRL_RX, VIRTIO_NET_F_CTRL_VLAN,
        VIRTIO_F_NOTIFY_ON_EMPTY,
index 58d2551..9e94c4b 100644 (file)
@@ -313,14 +313,6 @@ __vxge_hw_device_reg_addr_get(struct __vxge_hw_device *hldev)
                hldev->kdfc = (u8 __iomem *)(hldev->bar0 +
                        VXGE_HW_TOC_GET_KDFC_INITIAL_OFFSET(val64));
                break;
-       case 2:
-               hldev->kdfc = (u8 __iomem *)(hldev->bar1 +
-                       VXGE_HW_TOC_GET_KDFC_INITIAL_OFFSET(val64));
-               break;
-       case 4:
-               hldev->kdfc = (u8 __iomem *)(hldev->bar2 +
-                       VXGE_HW_TOC_GET_KDFC_INITIAL_OFFSET(val64));
-               break;
        default:
                break;
        }
@@ -831,8 +823,6 @@ vxge_hw_device_initialize(
                sizeof(struct vxge_hw_device_config));
 
        hldev->bar0 = attr->bar0;
-       hldev->bar1 = attr->bar1;
-       hldev->bar2 = attr->bar2;
        hldev->pdev = attr->pdev;
 
        hldev->uld_callbacks.link_up = attr->uld_callbacks.link_up;
index afbdf6f..224acea 100644 (file)
@@ -682,8 +682,6 @@ struct __vxge_hw_vpath_handle{
  * @major_revision: PCI Device major revision
  * @minor_revision: PCI Device minor revision
  * @bar0: BAR0 virtual address.
- * @bar1: BAR1 virtual address.
- * @bar2: BAR2 virtual address.
  * @pdev: Physical device handle
  * @config: Confguration passed by the LL driver at initialization
  * @link_state: Link state
@@ -698,8 +696,6 @@ struct __vxge_hw_device {
        u8                              major_revision;
        u8                              minor_revision;
        void __iomem                    *bar0;
-       void __iomem                    *bar1;
-       void __iomem                    *bar2;
        struct pci_dev                  *pdev;
        struct net_device               *ndev;
        struct vxge_hw_device_config    config;
@@ -788,17 +784,13 @@ struct vxge_hw_device_hw_info {
 /**
  * struct vxge_hw_device_attr - Device memory spaces.
  * @bar0: BAR0 virtual address.
- * @bar1: BAR1 virtual address.
- * @bar2: BAR2 virtual address.
  * @pdev: PCI device object.
  *
- * Device memory spaces. Includes configuration, BAR0, BAR1, etc. per device
+ * Device memory spaces. Includes configuration, BAR0 etc. per device
  * mapped memories. Also, includes a pointer to OS-specific PCI device object.
  */
 struct vxge_hw_device_attr {
        void __iomem            *bar0;
-       void __iomem            *bar1;
-       void __iomem            *bar2;
        struct pci_dev          *pdev;
        struct vxge_hw_uld_cbs  uld_callbacks;
 };
index 6034497..7b5402b 100644 (file)
@@ -374,10 +374,10 @@ vxge_rx_complete(struct vxge_ring *ring, struct sk_buff *skb, u16 vlan,
                if (ring->vlgrp && ext_info->vlan &&
                        (ring->vlan_tag_strip ==
                                VXGE_HW_VPATH_RPA_STRIP_VLAN_TAG_ENABLE))
-                       vlan_gro_receive(&ring->napi, ring->vlgrp,
+                       vlan_gro_receive(ring->napi_p, ring->vlgrp,
                                        ext_info->vlan, skb);
                else
-                       napi_gro_receive(&ring->napi, skb);
+                       napi_gro_receive(ring->napi_p, skb);
        } else {
                if (ring->vlgrp && vlan &&
                        (ring->vlan_tag_strip ==
@@ -454,6 +454,8 @@ vxge_rx_1b_compl(struct __vxge_hw_ring *ringh, void *dtr,
                vxge_hw_ring_rxd_1b_get(ringh, dtr, &dma_sizes);
                pkt_length = dma_sizes;
 
+               pkt_length -= ETH_FCS_LEN;
+
                vxge_debug_rx(VXGE_TRACE,
                        "%s: %s:%d  Packet Length = %d",
                        ring->ndev->name, __func__, __LINE__, pkt_length);
@@ -817,7 +819,6 @@ vxge_xmit(struct sk_buff *skb, struct net_device *dev)
        u64 dma_pointer;
        struct vxge_tx_priv *txdl_priv = NULL;
        struct __vxge_hw_fifo *fifo_hw;
-       u32 max_mss = 0x0;
        int offload_type;
        unsigned long flags = 0;
        int vpath_no = 0;
@@ -969,10 +970,6 @@ vxge_xmit(struct sk_buff *skb, struct net_device *dev)
 
                int mss = vxge_tcp_mss(skb);
                if (mss) {
-                       max_mss = dev->mtu + ETH_HLEN -
-                               VXGE_HW_TCPIP_HEADER_MAX_SIZE;
-                       if (mss > max_mss)
-                               mss = max_mss;
                        vxge_debug_tx(VXGE_TRACE,
                                "%s: %s:%d mss = %d",
                                dev->name, __func__, __LINE__, mss);
@@ -1000,7 +997,7 @@ vxge_xmit(struct sk_buff *skb, struct net_device *dev)
        VXGE_COMPLETE_VPATH_TX(fifo);
        vxge_debug_entryexit(VXGE_TRACE, "%s: %s:%d  Exiting...",
                dev->name, __func__, __LINE__);
-       return 0;
+       return NETDEV_TX_OK;
 
 _exit0:
        vxge_debug_tx(VXGE_TRACE, "%s: pci_map_page failed", dev->name);
@@ -1024,7 +1021,7 @@ _exit2:
        spin_unlock_irqrestore(&fifo->tx_lock, flags);
        VXGE_COMPLETE_VPATH_TX(fifo);
 
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 /*
@@ -2137,16 +2134,16 @@ int vxge_open_vpaths(struct vxgedev *vdev)
  */
 static irqreturn_t vxge_isr_napi(int irq, void *dev_id)
 {
-       struct __vxge_hw_device  *hldev = (struct __vxge_hw_device  *)dev_id;
-       struct vxgedev *vdev;
        struct net_device *dev;
+       struct __vxge_hw_device *hldev;
        u64 reason;
        enum vxge_hw_status status;
+       struct vxgedev *vdev = (struct vxgedev *) dev_id;;
 
        vxge_debug_intr(VXGE_TRACE, "%s:%d", __func__, __LINE__);
 
-       dev = hldev->ndev;
-       vdev = netdev_priv(dev);
+       dev = vdev->ndev;
+       hldev = (struct __vxge_hw_device *)pci_get_drvdata(vdev->pdev);
 
        if (pci_channel_offline(vdev->pdev))
                return IRQ_NONE;
@@ -2417,15 +2414,13 @@ static void vxge_rem_isr(struct vxgedev *vdev)
 #endif
        if (vdev->config.intr_type == INTA) {
                        synchronize_irq(vdev->pdev->irq);
-                       free_irq(vdev->pdev->irq, hldev);
+                       free_irq(vdev->pdev->irq, vdev);
        }
 }
 
 static int vxge_add_isr(struct vxgedev *vdev)
 {
        int ret = 0;
-       struct __vxge_hw_device  *hldev =
-               (struct __vxge_hw_device  *) pci_get_drvdata(vdev->pdev);
 #ifdef CONFIG_PCI_MSI
        int vp_idx = 0, intr_idx = 0, intr_cnt = 0, msix_idx = 0, irq_req = 0;
        u64 function_mode = vdev->config.device_hw_info.function_mode;
@@ -2579,7 +2574,7 @@ INTA_MODE:
        if (vdev->config.intr_type == INTA) {
                ret = request_irq((int) vdev->pdev->irq,
                        vxge_isr_napi,
-                       IRQF_SHARED, vdev->desc[0], hldev);
+                       IRQF_SHARED, vdev->desc[0], vdev);
                if (ret) {
                        vxge_debug_init(VXGE_ERR,
                                "%s %s-%d: ISR registration failed",
@@ -2712,11 +2707,15 @@ vxge_open(struct net_device *dev)
                netif_napi_add(dev, &vdev->napi, vxge_poll_inta,
                        vdev->config.napi_weight);
                napi_enable(&vdev->napi);
+               for (i = 0; i < vdev->no_of_vpath; i++)
+                       vdev->vpaths[i].ring.napi_p = &vdev->napi;
        } else {
                for (i = 0; i < vdev->no_of_vpath; i++) {
                        netif_napi_add(dev, &vdev->vpaths[i].ring.napi,
                            vxge_poll_msix, vdev->config.napi_weight);
                        napi_enable(&vdev->vpaths[i].ring.napi);
+                       vdev->vpaths[i].ring.napi_p =
+                               &vdev->vpaths[i].ring.napi;
                }
        }
 
@@ -2890,6 +2889,9 @@ int do_vxge_close(struct net_device *dev, int do_io)
        vdev = (struct vxgedev *)netdev_priv(dev);
        hldev = (struct __vxge_hw_device *) pci_get_drvdata(vdev->pdev);
 
+       if (unlikely(!is_vxge_card_up(vdev)))
+               return 0;
+
        /* If vxge_handle_crit_err task is executing,
         * wait till it completes. */
        while (test_and_set_bit(__VXGE_STATE_RESET_CARD, &vdev->state))
@@ -4152,18 +4154,6 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre)
                attr.bar0,
                (unsigned long long)pci_resource_start(pdev, 0));
 
-       attr.bar1 = pci_ioremap_bar(pdev, 2);
-       if (!attr.bar1) {
-               vxge_debug_init(VXGE_ERR,
-                       "%s : cannot remap io memory bar2", __func__);
-               ret = -ENODEV;
-               goto _exit3;
-       }
-       vxge_debug_ll_config(VXGE_TRACE,
-               "pci ioremap bar1: %p:0x%llx",
-               attr.bar1,
-               (unsigned long long)pci_resource_start(pdev, 2));
-
        status = vxge_hw_device_hw_info_get(attr.bar0,
                        &ll_config.device_hw_info);
        if (status != VXGE_HW_OK) {
@@ -4171,17 +4161,17 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre)
                        "%s: Reading of hardware info failed."
                        "Please try upgrading the firmware.", VXGE_DRIVER_NAME);
                ret = -EINVAL;
-               goto _exit4;
+               goto _exit3;
        }
 
        if (ll_config.device_hw_info.fw_version.major !=
-               VXGE_DRIVER_VERSION_MAJOR) {
+               VXGE_DRIVER_FW_VERSION_MAJOR) {
                vxge_debug_init(VXGE_ERR,
-                       "FW Ver.(maj): %d not driver's expected version: %d",
-                       ll_config.device_hw_info.fw_version.major,
-                       VXGE_DRIVER_VERSION_MAJOR);
+                       "%s: Incorrect firmware version."
+                       "Please upgrade the firmware to version 1.x.x",
+                       VXGE_DRIVER_NAME);
                ret = -EINVAL;
-               goto _exit4;
+               goto _exit3;
        }
 
        vpath_mask = ll_config.device_hw_info.vpath_mask;
@@ -4189,7 +4179,7 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre)
                vxge_debug_ll_config(VXGE_TRACE,
                        "%s: No vpaths available in device", VXGE_DRIVER_NAME);
                ret = -EINVAL;
-               goto _exit4;
+               goto _exit3;
        }
 
        vxge_debug_ll_config(VXGE_TRACE,
@@ -4222,7 +4212,7 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre)
                vxge_debug_ll_config(VXGE_ERR,
                        "%s: No more vpaths to configure", VXGE_DRIVER_NAME);
                ret = 0;
-               goto _exit4;
+               goto _exit3;
        }
 
        /* Setting driver callbacks */
@@ -4235,7 +4225,7 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre)
                vxge_debug_init(VXGE_ERR,
                        "Failed to initialize device (%d)", status);
                        ret = -EINVAL;
-                       goto _exit4;
+                       goto _exit3;
        }
 
        vxge_hw_device_debug_set(hldev, VXGE_ERR, VXGE_COMPONENT_LL);
@@ -4260,7 +4250,7 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre)
        if (vxge_device_register(hldev, &ll_config, high_dma, no_of_vpath,
                &vdev)) {
                ret = -EINVAL;
-               goto _exit5;
+               goto _exit4;
        }
 
        vxge_hw_device_debug_set(hldev, VXGE_TRACE, VXGE_COMPONENT_LL);
@@ -4271,7 +4261,6 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre)
        hldev->ndev = vdev->ndev;
        vdev->mtu = VXGE_HW_DEFAULT_MTU;
        vdev->bar0 = attr.bar0;
-       vdev->bar1 = attr.bar1;
        vdev->max_vpath_supported = max_vpath_supported;
        vdev->no_of_vpath = no_of_vpath;
 
@@ -4336,6 +4325,27 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre)
                ll_config.device_hw_info.fw_version.version,
                ll_config.device_hw_info.fw_date.date);
 
+       if (new_device) {
+               switch (ll_config.device_hw_info.function_mode) {
+               case VXGE_HW_FUNCTION_MODE_SINGLE_FUNCTION:
+                       vxge_debug_init(VXGE_TRACE,
+                       "%s: Single Function Mode Enabled", vdev->ndev->name);
+               break;
+               case VXGE_HW_FUNCTION_MODE_MULTI_FUNCTION:
+                       vxge_debug_init(VXGE_TRACE,
+                       "%s: Multi Function Mode Enabled", vdev->ndev->name);
+               break;
+               case VXGE_HW_FUNCTION_MODE_SRIOV:
+                       vxge_debug_init(VXGE_TRACE,
+                       "%s: Single Root IOV Mode Enabled", vdev->ndev->name);
+               break;
+               case VXGE_HW_FUNCTION_MODE_MRIOV:
+                       vxge_debug_init(VXGE_TRACE,
+                       "%s: Multi Root IOV Mode Enabled", vdev->ndev->name);
+               break;
+               }
+       }
+
        vxge_print_parm(vdev, vpath_mask);
 
        /* Store the fw version for ethttool option */
@@ -4353,7 +4363,7 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre)
                                "%s: mac_addr_list : memory allocation failed",
                                vdev->ndev->name);
                        ret = -EPERM;
-                       goto _exit6;
+                       goto _exit5;
                }
                macaddr = (u8 *)&entry->macaddr;
                memcpy(macaddr, vdev->ndev->dev_addr, ETH_ALEN);
@@ -4361,6 +4371,7 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre)
                vdev->vpaths[i].mac_addr_cnt = 1;
        }
 
+       kfree(device_config);
        vxge_debug_entryexit(VXGE_TRACE, "%s: %s:%d  Exiting...",
                vdev->ndev->name, __func__, __LINE__);
 
@@ -4370,16 +4381,14 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre)
 
        return 0;
 
-_exit6:
+_exit5:
        for (i = 0; i < vdev->no_of_vpath; i++)
                vxge_free_mac_add_list(&vdev->vpaths[i]);
 
        vxge_device_unregister(hldev);
-_exit5:
+_exit4:
        pci_disable_sriov(pdev);
        vxge_hw_device_terminate(hldev);
-_exit4:
-       iounmap(attr.bar1);
 _exit3:
        iounmap(attr.bar0);
 _exit2:
@@ -4438,7 +4447,6 @@ vxge_remove(struct pci_dev *pdev)
        kfree(vdev->vpaths);
 
        iounmap(vdev->bar0);
-       iounmap(vdev->bar1);
 
        pci_disable_sriov(pdev);
 
index 9704b2b..18d824c 100644 (file)
@@ -21,7 +21,7 @@
 
 #define VXGE_DRIVER_NAME               "vxge"
 #define VXGE_DRIVER_VENDOR             "Neterion, Inc"
-#define VXGE_DRIVER_VERSION_MAJOR 0
+#define VXGE_DRIVER_FW_VERSION_MAJOR   1
 
 #define DRV_VERSION    VXGE_VERSION_MAJOR"."VXGE_VERSION_MINOR"."\
        VXGE_VERSION_FIX"."VXGE_VERSION_BUILD"-"\
@@ -260,6 +260,7 @@ struct vxge_ring {
        int gro_enable;
 
        struct napi_struct napi;
+       struct napi_struct *napi_p;
 
 #define VXGE_MAX_MAC_ADDR_COUNT                30
 
@@ -363,7 +364,6 @@ struct vxgedev {
 
        struct __vxge_hw_vpath_handle *vp_handles[VXGE_HW_MAX_VIRTUAL_PATHS];
        void __iomem *bar0;
-       void __iomem *bar1;
        struct vxge_sw_stats    stats;
        int             mtu;
        /* Below variables are used for vpath selection to transmit a packet */
index 10f4da3..9a3b823 100644 (file)
@@ -1784,7 +1784,7 @@ struct vxge_hw_mrpcim_reg {
 #define        VXGE_HW_XMAC_GEN_ERR_REG_XMACJ_XMAC_FSM_ERR     vxge_mBIT(63)
 /*0x01e18*/    u64     xmac_gen_err_mask;
 /*0x01e20*/    u64     xmac_gen_err_alarm;
-/*0x01e28*/    u64     xmac_link_err_port_reg[2];
+/*0x01e28*/    u64     xmac_link_err_port0_reg;
 #define        VXGE_HW_XMAC_LINK_ERR_PORT_REG_XMACJ_PORT_DOWN  vxge_mBIT(3)
 #define        VXGE_HW_XMAC_LINK_ERR_PORT_REG_XMACJ_PORT_UP    vxge_mBIT(7)
 #define        VXGE_HW_XMAC_LINK_ERR_PORT_REG_XMACJ_PORT_WENT_DOWN     vxge_mBIT(11)
@@ -1798,8 +1798,11 @@ struct vxge_hw_mrpcim_reg {
 #define        VXGE_HW_XMAC_LINK_ERR_PORT_REG_RATEMGMT_LASI_INV        vxge_mBIT(39)
 #define        VXGE_HW_XMAC_LINK_ERR_PORT_REG_XMDIO_MDIO_MGR_ACCESS_COMPLETE \
                                                                vxge_mBIT(47)
-/*0x01e30*/    u64     xmac_link_err_port_mask[2];
-/*0x01e38*/    u64     xmac_link_err_port_alarm[2];
+/*0x01e30*/    u64     xmac_link_err_port0_mask;
+/*0x01e38*/    u64     xmac_link_err_port0_alarm;
+/*0x01e40*/    u64     xmac_link_err_port1_reg;
+/*0x01e48*/    u64     xmac_link_err_port1_mask;
+/*0x01e50*/    u64     xmac_link_err_port1_alarm;
 /*0x01e58*/    u64     xgxs_gen_err_reg;
 #define        VXGE_HW_XGXS_GEN_ERR_REG_XGXS_XGXS_FSM_ERR      vxge_mBIT(63)
 /*0x01e60*/    u64     xgxs_gen_err_mask;
index 7567a11..8260b91 100644 (file)
@@ -35,8 +35,6 @@
                        VXGE_HW_HEADER_VLAN_SIZE + \
                        VXGE_HW_HEADER_SNAP_SIZE)
 
-#define VXGE_HW_TCPIP_HEADER_MAX_SIZE  (64 + 64)
-
 /* 32bit alignments */
 #define VXGE_HW_HEADER_ETHERNET_II_802_3_ALIGN         2
 #define VXGE_HW_HEADER_802_2_SNAP_ALIGN                        2
index 82786ff..580c6eb 100644 (file)
@@ -18,6 +18,6 @@
 #define VXGE_VERSION_MAJOR     "2"
 #define VXGE_VERSION_MINOR     "0"
 #define VXGE_VERSION_FIX       "4"
-#define VXGE_VERSION_BUILD     "17795"
+#define VXGE_VERSION_BUILD     "17899"
 #define VXGE_VERSION_FOR       "k"
 #endif
index f525f9f..4ae9bd2 100644 (file)
@@ -663,7 +663,7 @@ static int cycx_netdevice_hard_start_xmit(struct sk_buff *skb,
 free_packet:
        dev_kfree_skb(skb);
 
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 /* Get Ethernet-style interface statistics.
index 2fa275a..8526b6d 100644 (file)
@@ -194,7 +194,7 @@ static int dlci_transmit(struct sk_buff *skb, struct net_device *dev)
        ret = 0;
 
        if (!skb || !dev)
-               return(0);
+               return NETDEV_TX_OK;
 
        dlp = netdev_priv(dev);
 
@@ -219,7 +219,7 @@ static int dlci_transmit(struct sk_buff *skb, struct net_device *dev)
        /* Alan Cox recommends always returning 0, and always freeing the packet */
        /* experience suggest a slightly more conservative approach */
 
-       if (!ret)
+       if (ret == NETDEV_TX_OK)
        {
                dev_kfree_skb(skb);
                netif_wake_queue(dev);
index 8face5d..e81946d 100644 (file)
@@ -1182,7 +1182,7 @@ static int dscc4_start_xmit(struct sk_buff *skb, struct net_device *dev)
        if (dscc4_tx_quiescent(dpriv, dev))
                dscc4_do_tx(dpriv, dev);
 
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 static int dscc4_close(struct net_device *dev)
index 25c9ef6..20a1237 100644 (file)
@@ -792,25 +792,6 @@ fst_process_rx_status(int rx_status, char *name)
                         */
                        break;
                }
-
-       case NET_RX_CN_LOW:
-               {
-                       dbg(DBG_ASS, "%s: Receive Low Congestion\n", name);
-                       break;
-               }
-
-       case NET_RX_CN_MOD:
-               {
-                       dbg(DBG_ASS, "%s: Receive Moderate Congestion\n", name);
-                       break;
-               }
-
-       case NET_RX_CN_HIGH:
-               {
-                       dbg(DBG_ASS, "%s: Receive High Congestion\n", name);
-                       break;
-               }
-
        case NET_RX_DROP:
                {
                        dbg(DBG_ASS, "%s: Received packet dropped\n", name);
@@ -2313,7 +2294,7 @@ fst_start_xmit(struct sk_buff *skb, struct net_device *dev)
                dbg(DBG_ASS,
                    "Tried to transmit but no carrier on card %d port %d\n",
                    card->card_no, port->index);
-               return 0;
+               return NETDEV_TX_OK;
        }
 
        /* Drop it if it's too big! MTU failure ? */
@@ -2322,7 +2303,7 @@ fst_start_xmit(struct sk_buff *skb, struct net_device *dev)
                    LEN_TX_BUFFER);
                dev_kfree_skb(skb);
                dev->stats.tx_errors++;
-               return 0;
+               return NETDEV_TX_OK;
        }
 
        /*
@@ -2356,7 +2337,7 @@ fst_start_xmit(struct sk_buff *skb, struct net_device *dev)
                dev->stats.tx_errors++;
                dbg(DBG_ASS, "Tx queue overflow card %d port %d\n",
                    card->card_no, port->index);
-               return 0;
+               return NETDEV_TX_OK;
        }
 
        /*
@@ -2373,7 +2354,7 @@ fst_start_xmit(struct sk_buff *skb, struct net_device *dev)
        fst_q_work_item(&fst_work_txq, card->card_no);
        tasklet_schedule(&fst_tx_task);
 
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 /*
index bfa0161..52438c7 100644 (file)
@@ -421,7 +421,7 @@ static int pvc_xmit(struct sk_buff *skb, struct net_device *dev)
                                                             GFP_ATOMIC)) {
                                                dev->stats.tx_dropped++;
                                                dev_kfree_skb(skb);
-                                               return 0;
+                                               return NETDEV_TX_OK;
                                        }
                                skb_put(skb, pad);
                                memset(skb->data + len, 0, pad);
@@ -435,13 +435,13 @@ static int pvc_xmit(struct sk_buff *skb, struct net_device *dev)
                                dev->stats.tx_compressed++;
                        skb->dev = pvc->frad;
                        dev_queue_xmit(skb);
-                       return 0;
+                       return NETDEV_TX_OK;
                }
        }
 
        dev->stats.tx_dropped++;
        dev_kfree_skb(skb);
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 static inline void fr_log_dlci_active(pvc_device *pvc)
index 45b1822..d1492ae 100644 (file)
@@ -1428,7 +1428,7 @@ static int lmc_start_xmit(struct sk_buff *skb, struct net_device *dev)
     lmc_softc_t *sc = dev_to_sc(dev);
     u32 flag;
     int entry;
-    int ret = 0;
+    int ret = NETDEV_TX_OK;
     unsigned long flags;
 
     lmc_trace(dev, "lmc_start_xmit in");
index 3fb9dbc..545178e 100644 (file)
@@ -465,7 +465,7 @@ sbni_start_xmit( struct sk_buff  *skb,  struct net_device  *dev )
                        prepare_to_send( skb, p );
                        spin_unlock( &nl->lock );
                        netif_start_queue( dev );
-                       return  0;
+                       return NETDEV_TX_OK;
                }
        }
 
@@ -485,7 +485,7 @@ sbni_start_xmit( struct sk_buff  *skb,  struct net_device  *dev )
        prepare_to_send( skb, dev );
 
        spin_unlock( &nl->lock );
-       return  0;
+       return NETDEV_TX_OK;
 }
 
 #endif /* CONFIG_SBNI_MULTILINE */
index e4ad7b6..03b76ad 100644 (file)
@@ -310,7 +310,7 @@ static int wanxl_xmit(struct sk_buff *skb, struct net_device *dev)
        }
 
        spin_unlock(&port->lock);
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 
index d67e208..1047920 100644 (file)
@@ -308,7 +308,7 @@ static int x25_asy_xmit(struct sk_buff *skb, struct net_device *dev)
                printk(KERN_ERR "%s: xmit call when iface is down\n",
                        dev->name);
                kfree_skb(skb);
-               return 0;
+               return NETDEV_TX_OK;
        }
 
        switch (skb->data[0]) {
@@ -319,14 +319,14 @@ static int x25_asy_xmit(struct sk_buff *skb, struct net_device *dev)
                if (err != LAPB_OK)
                        printk(KERN_ERR "x25_asy: lapb_connect_request error - %d\n", err);
                kfree_skb(skb);
-               return 0;
+               return NETDEV_TX_OK;
        case 0x02: /* Disconnect request .. do nothing - hang up ?? */
                err = lapb_disconnect_request(dev);
                if (err != LAPB_OK)
                        printk(KERN_ERR "x25_asy: lapb_disconnect_request error - %d\n", err);
        default:
                kfree_skb(skb);
-               return  0;
+               return NETDEV_TX_OK;
        }
        skb_pull(skb, 1);       /* Remove control byte */
        /*
@@ -344,9 +344,9 @@ static int x25_asy_xmit(struct sk_buff *skb, struct net_device *dev)
        if (err != LAPB_OK) {
                printk(KERN_ERR "x25_asy: lapb_data_request error - %d\n", err);
                kfree_skb(skb);
-               return 0;
+               return NETDEV_TX_OK;
        }
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 
index 2b9e379..ecc9383 100644 (file)
@@ -452,7 +452,8 @@ static void adm8211_interrupt_rci(struct ieee80211_hw *dev)
                        rx_status.freq = adm8211_channels[priv->channel - 1].center_freq;
                        rx_status.band = IEEE80211_BAND_2GHZ;
 
-                       ieee80211_rx_irqsafe(dev, skb, &rx_status);
+                       memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status));
+                       ieee80211_rx_irqsafe(dev, skb);
                }
 
                entry = (++priv->cur_rx) % priv->rx_ring_size;
index c70604f..49f3139 100644 (file)
@@ -1927,7 +1927,7 @@ static int mpi_start_xmit(struct sk_buff *skb, struct net_device *dev) {
 
        if (!skb) {
                airo_print_err(dev->name, "%s: skb == NULL!",__func__);
-               return 0;
+               return NETDEV_TX_OK;
        }
        npacks = skb_queue_len (&ai->txq);
 
@@ -1938,7 +1938,7 @@ static int mpi_start_xmit(struct sk_buff *skb, struct net_device *dev) {
                        return NETDEV_TX_BUSY;
                }
                skb_queue_tail (&ai->txq, skb);
-               return 0;
+               return NETDEV_TX_OK;
        }
 
        spin_lock_irqsave(&ai->aux_lock, flags);
@@ -1951,7 +1951,7 @@ static int mpi_start_xmit(struct sk_buff *skb, struct net_device *dev) {
                set_bit(FLAG_PENDING_XMIT, &ai->flags);
                mpi_send_packet (dev);
        }
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 /*
@@ -2127,7 +2127,7 @@ static int airo_start_xmit(struct sk_buff *skb, struct net_device *dev) {
 
        if ( skb == NULL ) {
                airo_print_err(dev->name, "%s: skb == NULL!", __func__);
-               return 0;
+               return NETDEV_TX_OK;
        }
 
        /* Find a vacant FID */
@@ -2155,7 +2155,7 @@ static int airo_start_xmit(struct sk_buff *skb, struct net_device *dev) {
                wake_up_interruptible(&priv->thr_wait);
        } else
                airo_end_xmit(dev);
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 static void airo_end_xmit11(struct net_device *dev) {
@@ -2199,7 +2199,7 @@ static int airo_start_xmit11(struct sk_buff *skb, struct net_device *dev) {
 
        if ( skb == NULL ) {
                airo_print_err(dev->name, "%s: skb == NULL!", __func__);
-               return 0;
+               return NETDEV_TX_OK;
        }
 
        /* Find a vacant FID */
@@ -2227,7 +2227,7 @@ static int airo_start_xmit11(struct sk_buff *skb, struct net_device *dev) {
                wake_up_interruptible(&priv->thr_wait);
        } else
                airo_end_xmit11(dev);
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 static void airo_read_stats(struct net_device *dev)
index d84caf1..d479f47 100644 (file)
@@ -1193,7 +1193,7 @@ static int arlan_tx(struct sk_buff *skb, struct net_device *dev)
 
        arlan_process_interrupt(dev);
        ARLAN_DEBUG_EXIT("arlan_tx");
-       return 0;
+       return NETDEV_TX_OK;
 
 bad_end:
        arlan_process_interrupt(dev);
index 4efbdbe..13303fa 100644 (file)
@@ -1568,7 +1568,8 @@ static void at76_rx_tasklet(unsigned long param)
 
        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);
+       memcpy(IEEE80211_SKB_RXCB(priv->rx_skb), &rx_status, sizeof(rx_status));
+       ieee80211_rx_irqsafe(priv->hw, priv->rx_skb);
 
        /* Use a new skb for the next receive */
        priv->rx_skb = NULL;
index 9d38cf6..51753ed 100644 (file)
@@ -917,8 +917,10 @@ static void ar9170_handle_mpdu(struct ar9170 *ar, u8 *buf, int len)
                ar9170_rx_phy_status(ar, phy, &status);
 
        skb = ar9170_rx_copy_data(buf, mpdu_len);
-       if (likely(skb))
-               ieee80211_rx_irqsafe(ar->hw, skb, &status);
+       if (likely(skb)) {
+               memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status));
+               ieee80211_rx_irqsafe(ar->hw, skb);
+       }
 }
 
 void ar9170_rx(struct ar9170 *ar, struct sk_buff *skb)
index 754b1f8..1aec7af 100644 (file)
@@ -779,7 +779,7 @@ static int ar9170_usb_probe(struct usb_interface *intf,
        aru->req_one_stage_fw = ar9170_requires_one_stage(id);
 
        usb_set_intfdata(intf, aru);
-       SET_IEEE80211_DEV(ar->hw, &udev->dev);
+       SET_IEEE80211_DEV(ar->hw, &intf->dev);
 
        init_usb_anchor(&aru->rx_submitted);
        init_usb_anchor(&aru->tx_pending);
index 6358233..9137511 100644 (file)
@@ -713,8 +713,8 @@ struct ath5k_gain {
  * Used internaly for reset_tx_queue).
  * Also see struct struct ieee80211_channel.
  */
-#define IS_CHAN_XR(_c) ((_c.hw_value & CHANNEL_XR) != 0)
-#define IS_CHAN_B(_c)  ((_c.hw_value & CHANNEL_B) != 0)
+#define IS_CHAN_XR(_c) ((_c->hw_value & CHANNEL_XR) != 0)
+#define IS_CHAN_B(_c)  ((_c->hw_value & CHANNEL_B) != 0)
 
 /*
  * The following structure is used to map 2GHz channels to
@@ -1029,14 +1029,15 @@ struct ath5k_hw {
        enum ath5k_int          ah_imr;
 
        enum nl80211_iftype     ah_op_mode;
-       enum ath5k_power_mode   ah_power_mode;
-       struct ieee80211_channel ah_current_channel;
+       struct ieee80211_channel *ah_current_channel;
        bool                    ah_turbo;
        bool                    ah_calibration;
-       bool                    ah_running;
        bool                    ah_single_chip;
        bool                    ah_combined_mic;
 
+       enum ath5k_version      ah_version;
+       enum ath5k_radio        ah_radio;
+       u32                     ah_phy;
        u32                     ah_mac_srev;
        u16                     ah_mac_version;
        u16                     ah_mac_revision;
@@ -1044,13 +1045,6 @@ struct ath5k_hw {
        u16                     ah_radio_5ghz_revision;
        u16                     ah_radio_2ghz_revision;
 
-       enum ath5k_version      ah_version;
-       enum ath5k_radio        ah_radio;
-       u32                     ah_phy;
-
-       bool                    ah_5ghz;
-       bool                    ah_2ghz;
-
 #define ah_modes               ah_capabilities.cap_mode
 #define ah_ee_version          ah_capabilities.cap_eeprom.ee_version
 
@@ -1058,7 +1052,6 @@ struct ath5k_hw {
        u32                     ah_aifs;
        u32                     ah_cw_min;
        u32                     ah_cw_max;
-       bool                    ah_software_retry;
        u32                     ah_limit_tx_retries;
 
        /* Antenna Control */
@@ -1066,6 +1059,7 @@ struct ath5k_hw {
        u8                      ah_ant_mode;
        u8                      ah_tx_ant;
        u8                      ah_def_ant;
+       bool                    ah_software_retry;
 
        u8                      ah_sta_id[ETH_ALEN];
 
@@ -1075,7 +1069,6 @@ struct ath5k_hw {
        u8                      ah_bssid[ETH_ALEN];
        u8                      ah_bssid_mask[ETH_ALEN];
 
-       u32                     ah_gpio[AR5K_MAX_GPIO];
        int                     ah_gpio_npins;
 
        struct ath_regulatory   ah_regulatory;
index c41ef58..9a84d94 100644 (file)
@@ -319,6 +319,9 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version)
 
        ath5k_hw_rfgain_opt_init(ah);
 
+       /* turn on HW LEDs */
+       ath5k_hw_set_ledstate(ah, AR5K_LED_INIT);
+
        return ah;
 err_free:
        kfree(ah);
index 029c1bc..7db32ce 100644 (file)
@@ -218,6 +218,8 @@ static struct pci_driver ath5k_pci_driver = {
  * Prototypes - MAC 802.11 stack related functions
  */
 static int ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb);
+static int ath5k_tx_queue(struct ieee80211_hw *hw, struct sk_buff *skb,
+               struct ath5k_txq *txq);
 static int ath5k_reset(struct ath5k_softc *sc, struct ieee80211_channel *chan);
 static int ath5k_reset_wake(struct ath5k_softc *sc);
 static int ath5k_start(struct ieee80211_hw *hw);
@@ -248,6 +250,8 @@ static void ath5k_bss_info_changed(struct ieee80211_hw *hw,
                struct ieee80211_vif *vif,
                struct ieee80211_bss_conf *bss_conf,
                u32 changes);
+static void ath5k_sw_scan_start(struct ieee80211_hw *hw);
+static void ath5k_sw_scan_complete(struct ieee80211_hw *hw);
 
 static const struct ieee80211_ops ath5k_hw_ops = {
        .tx             = ath5k_tx,
@@ -265,6 +269,8 @@ static const struct ieee80211_ops ath5k_hw_ops = {
        .set_tsf        = ath5k_set_tsf,
        .reset_tsf      = ath5k_reset_tsf,
        .bss_info_changed = ath5k_bss_info_changed,
+       .sw_scan_start  = ath5k_sw_scan_start,
+       .sw_scan_complete = ath5k_sw_scan_complete,
 };
 
 /*
@@ -297,7 +303,8 @@ static void ath5k_desc_free(struct ath5k_softc *sc,
 static int     ath5k_rxbuf_setup(struct ath5k_softc *sc,
                                struct ath5k_buf *bf);
 static int     ath5k_txbuf_setup(struct ath5k_softc *sc,
-                               struct ath5k_buf *bf);
+                               struct ath5k_buf *bf,
+                               struct ath5k_txq *txq);
 static inline void ath5k_txbuf_free(struct ath5k_softc *sc,
                                struct ath5k_buf *bf)
 {
@@ -512,6 +519,7 @@ ath5k_pci_probe(struct pci_dev *pdev,
        /* Initialize driver private data */
        SET_IEEE80211_DEV(hw, &pdev->dev);
        hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
+                   IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
                    IEEE80211_HW_SIGNAL_DBM |
                    IEEE80211_HW_NOISE_DBM;
 
@@ -666,7 +674,6 @@ ath5k_pci_suspend(struct pci_dev *pdev, pm_message_t state)
 
        ath5k_led_off(sc);
 
-       free_irq(pdev->irq, sc);
        pci_save_state(pdev);
        pci_disable_device(pdev);
        pci_set_power_state(pdev, PCI_D3hot);
@@ -694,18 +701,8 @@ ath5k_pci_resume(struct pci_dev *pdev)
         */
        pci_write_config_byte(pdev, 0x41, 0);
 
-       err = request_irq(pdev->irq, ath5k_intr, IRQF_SHARED, "ath", sc);
-       if (err) {
-               ATH5K_ERR(sc, "request_irq failed\n");
-               goto err_no_irq;
-       }
-
        ath5k_led_enable(sc);
        return 0;
-
-err_no_irq:
-       pci_disable_device(pdev);
-       return err;
 }
 #endif /* CONFIG_PM */
 
@@ -785,12 +782,18 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw)
                goto err_desc;
        }
        sc->bhalq = ret;
+       sc->cabq = ath5k_txq_setup(sc, AR5K_TX_QUEUE_CAB, 0);
+       if (IS_ERR(sc->cabq)) {
+               ATH5K_ERR(sc, "can't setup cab queue\n");
+               ret = PTR_ERR(sc->cabq);
+               goto err_bhal;
+       }
 
        sc->txq = ath5k_txq_setup(sc, AR5K_TX_QUEUE_DATA, AR5K_WME_AC_BK);
        if (IS_ERR(sc->txq)) {
                ATH5K_ERR(sc, "can't setup xmit queue\n");
                ret = PTR_ERR(sc->txq);
-               goto err_bhal;
+               goto err_queues;
        }
 
        tasklet_init(&sc->rxtq, ath5k_tasklet_rx, (unsigned long)sc);
@@ -1228,10 +1231,10 @@ ath5k_rxbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf)
 }
 
 static int
-ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf)
+ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf,
+                 struct ath5k_txq *txq)
 {
        struct ath5k_hw *ah = sc->ah;
-       struct ath5k_txq *txq = sc->txq;
        struct ath5k_desc *ds = bf->desc;
        struct sk_buff *skb = bf->skb;
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
@@ -1901,7 +1904,8 @@ accept:
                if (sc->opmode == NL80211_IFTYPE_ADHOC)
                        ath5k_check_ibss_tsf(sc, skb, &rxs);
 
-               __ieee80211_rx(sc->hw, skb, &rxs);
+               memcpy(IEEE80211_SKB_RXCB(skb), &rxs, sizeof(rxs));
+               ieee80211_rx(sc->hw, skb);
 
                bf->skb = next_skb;
                bf->skbaddr = next_skb_addr;
@@ -2078,13 +2082,6 @@ err_unmap:
        return ret;
 }
 
-static void ath5k_beacon_disable(struct ath5k_softc *sc)
-{
-       sc->imask &= ~(AR5K_INT_BMISS | AR5K_INT_SWBA);
-       ath5k_hw_set_imr(sc->ah, sc->imask);
-       ath5k_hw_stop_tx_dma(sc->ah, sc->bhalq);
-}
-
 /*
  * Transmit a beacon frame at SWBA.  Dynamic updates to the
  * frame contents are done as needed and the slot time is
@@ -2098,6 +2095,7 @@ ath5k_beacon_send(struct ath5k_softc *sc)
 {
        struct ath5k_buf *bf = sc->bbuf;
        struct ath5k_hw *ah = sc->ah;
+       struct sk_buff *skb;
 
        ATH5K_DBG_UNLIMIT(sc, ATH5K_DEBUG_BEACON, "in beacon_send\n");
 
@@ -2151,6 +2149,12 @@ ath5k_beacon_send(struct ath5k_softc *sc)
        ATH5K_DBG(sc, ATH5K_DEBUG_BEACON, "TXDP[%u] = %llx (%p)\n",
                sc->bhalq, (unsigned long long)bf->daddr, bf->desc);
 
+       skb = ieee80211_get_buffered_bc(sc->hw, sc->vif);
+       while (skb) {
+               ath5k_tx_queue(sc->hw, skb, sc->cabq);
+               skb = ieee80211_get_buffered_bc(sc->hw, sc->vif);
+       }
+
        sc->bsent++;
 }
 
@@ -2271,13 +2275,11 @@ ath5k_beacon_config(struct ath5k_softc *sc)
        struct ath5k_hw *ah = sc->ah;
        unsigned long flags;
 
-       ath5k_hw_set_imr(ah, 0);
+       spin_lock_irqsave(&sc->block, flags);
        sc->bmisscount = 0;
        sc->imask &= ~(AR5K_INT_BMISS | AR5K_INT_SWBA);
 
-       if (sc->opmode == NL80211_IFTYPE_ADHOC ||
-                       sc->opmode == NL80211_IFTYPE_MESH_POINT ||
-                       sc->opmode == NL80211_IFTYPE_AP) {
+       if (sc->enable_beacon) {
                /*
                 * In IBSS mode we use a self-linked tx descriptor and let the
                 * hardware send the beacons automatically. We have to load it
@@ -2290,16 +2292,17 @@ ath5k_beacon_config(struct ath5k_softc *sc)
                sc->imask |= AR5K_INT_SWBA;
 
                if (sc->opmode == NL80211_IFTYPE_ADHOC) {
-                       if (ath5k_hw_hasveol(ah)) {
-                               spin_lock_irqsave(&sc->block, flags);
+                       if (ath5k_hw_hasveol(ah))
                                ath5k_beacon_send(sc);
-                               spin_unlock_irqrestore(&sc->block, flags);
-                       }
                } else
                        ath5k_beacon_update_timers(sc, -1);
+       } else {
+               ath5k_hw_stop_tx_dma(sc->ah, sc->bhalq);
        }
 
        ath5k_hw_set_imr(ah, sc->imask);
+       mmiowb();
+       spin_unlock_irqrestore(&sc->block, flags);
 }
 
 static void ath5k_tasklet_beacon(unsigned long data)
@@ -2598,6 +2601,14 @@ static int
 ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
 {
        struct ath5k_softc *sc = hw->priv;
+
+       return ath5k_tx_queue(hw, skb, sc->txq);
+}
+
+static int ath5k_tx_queue(struct ieee80211_hw *hw, struct sk_buff *skb,
+                         struct ath5k_txq *txq)
+{
+       struct ath5k_softc *sc = hw->priv;
        struct ath5k_buf *bf;
        unsigned long flags;
        int hdrlen;
@@ -2641,7 +2652,7 @@ ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
 
        bf->skb = skb;
 
-       if (ath5k_txbuf_setup(sc, bf)) {
+       if (ath5k_txbuf_setup(sc, bf, txq)) {
                bf->skb = NULL;
                spin_lock_irqsave(&sc->txbuflock, flags);
                list_add_tail(&bf->list, &sc->txbuf);
@@ -2676,7 +2687,7 @@ ath5k_reset(struct ath5k_softc *sc, struct ieee80211_channel *chan)
                sc->curchan = chan;
                sc->curband = &sc->sbands[chan->band];
        }
-       ret = ath5k_hw_reset(ah, sc->opmode, sc->curchan, true);
+       ret = ath5k_hw_reset(ah, sc->opmode, sc->curchan, chan != NULL);
        if (ret) {
                ATH5K_ERR(sc, "can't reset hardware (%d)\n", ret);
                goto err;
@@ -2776,7 +2787,6 @@ ath5k_remove_interface(struct ieee80211_hw *hw,
                goto end;
 
        ath5k_hw_set_lladdr(sc->ah, mac);
-       ath5k_beacon_disable(sc);
        sc->vif = NULL;
 end:
        mutex_unlock(&sc->lock);
@@ -3108,25 +3118,6 @@ out:
        return ret;
 }
 
-/*
- *  Update the beacon and reconfigure the beacon queues.
- */
-static void
-ath5k_beacon_reconfig(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
-{
-       int ret;
-       unsigned long flags;
-       struct ath5k_softc *sc = hw->priv;
-
-       spin_lock_irqsave(&sc->block, flags);
-       ret = ath5k_beacon_update(hw, vif);
-       spin_unlock_irqrestore(&sc->block, flags);
-       if (ret == 0) {
-               ath5k_beacon_config(sc);
-               mmiowb();
-       }
-}
-
 static void
 set_beacon_filter(struct ieee80211_hw *hw, bool enable)
 {
@@ -3149,6 +3140,7 @@ static void ath5k_bss_info_changed(struct ieee80211_hw *hw,
 {
        struct ath5k_softc *sc = hw->priv;
        struct ath5k_hw *ah = sc->ah;
+       unsigned long flags;
 
        mutex_lock(&sc->lock);
        if (WARN_ON(sc->vif != vif))
@@ -3170,15 +3162,37 @@ static void ath5k_bss_info_changed(struct ieee80211_hw *hw,
                sc->assoc = bss_conf->assoc;
                if (sc->opmode == NL80211_IFTYPE_STATION)
                        set_beacon_filter(hw, sc->assoc);
+               ath5k_hw_set_ledstate(sc->ah, sc->assoc ?
+                       AR5K_LED_ASSOC : AR5K_LED_INIT);
        }
 
-       if (changes & BSS_CHANGED_BEACON &&
-           (vif->type == NL80211_IFTYPE_ADHOC ||
-            vif->type == NL80211_IFTYPE_MESH_POINT ||
-            vif->type == NL80211_IFTYPE_AP)) {
-               ath5k_beacon_reconfig(hw, vif);
+       if (changes & BSS_CHANGED_BEACON) {
+               spin_lock_irqsave(&sc->block, flags);
+               ath5k_beacon_update(hw, vif);
+               spin_unlock_irqrestore(&sc->block, flags);
        }
 
+       if (changes & BSS_CHANGED_BEACON_ENABLED)
+               sc->enable_beacon = bss_conf->enable_beacon;
+
+       if (changes & (BSS_CHANGED_BEACON | BSS_CHANGED_BEACON_ENABLED |
+                      BSS_CHANGED_BEACON_INT))
+               ath5k_beacon_config(sc);
+
  unlock:
        mutex_unlock(&sc->lock);
 }
+
+static void ath5k_sw_scan_start(struct ieee80211_hw *hw)
+{
+       struct ath5k_softc *sc = hw->priv;
+       if (!sc->assoc)
+               ath5k_hw_set_ledstate(sc->ah, AR5K_LED_SCAN);
+}
+
+static void ath5k_sw_scan_complete(struct ieee80211_hw *hw)
+{
+       struct ath5k_softc *sc = hw->priv;
+       ath5k_hw_set_ledstate(sc->ah, sc->assoc ?
+               AR5K_LED_ASSOC : AR5K_LED_INIT);
+}
index f9b7f2f..778e422 100644 (file)
@@ -114,8 +114,7 @@ struct ath5k_softc {
        struct pci_dev          *pdev;          /* for dma mapping */
        void __iomem            *iobase;        /* address of the device */
        struct mutex            lock;           /* dev-level lock */
-       /* FIXME: how many does it really need? */
-       struct ieee80211_tx_queue_stats tx_stats[16];
+       struct ieee80211_tx_queue_stats tx_stats[AR5K_NUM_TX_QUEUES];
        struct ieee80211_low_level_stats ll_stats;
        struct ieee80211_hw     *hw;            /* IEEE 802.11 common */
        struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS];
@@ -171,9 +170,8 @@ struct ath5k_softc {
        struct list_head        txbuf;          /* transmit buffer */
        spinlock_t              txbuflock;
        unsigned int            txbuf_len;      /* buf count in txbuf list */
-       struct ath5k_txq        txqs[2];        /* beacon and tx */
-
-       struct ath5k_txq        *txq;           /* beacon and tx*/
+       struct ath5k_txq        txqs[AR5K_NUM_TX_QUEUES];       /* tx queues */
+       struct ath5k_txq        *txq;           /* main tx queue */
        struct tasklet_struct   txtq;           /* tx intr tasklet */
        struct ath5k_led        tx_led;         /* tx led */
 
@@ -187,10 +185,12 @@ struct ath5k_softc {
                                bintval,        /* beacon interval in TU */
                                bsent;
        unsigned int            nexttbtt;       /* next beacon time in TU */
+       struct ath5k_txq        *cabq;          /* content after beacon */
 
        struct timer_list       calib_tim;      /* calibration timer */
        int                     power_level;    /* Requested tx power in dbm */
        bool                    assoc;          /* assocate state */
+       bool                    enable_beacon;  /* true if beacons are on */
 };
 
 #define ath5k_hw_hasbssidmask(_ah) \
index 4904a07..747508c 100644 (file)
@@ -380,13 +380,15 @@ ath5k_debug_init_device(struct ath5k_softc *sc)
        sc->debug.debugfs_phydir = debugfs_create_dir(wiphy_name(sc->hw->wiphy),
                                ath5k_global_debugfs);
 
-       sc->debug.debugfs_debug = debugfs_create_file("debug", S_IWUSR | S_IRUGO,
+       sc->debug.debugfs_debug = debugfs_create_file("debug",
+                               S_IWUSR | S_IRUSR,
                                sc->debug.debugfs_phydir, sc, &fops_debug);
 
-       sc->debug.debugfs_registers = debugfs_create_file("registers", S_IRUGO,
+       sc->debug.debugfs_registers = debugfs_create_file("registers", S_IRUSR,
                                sc->debug.debugfs_phydir, sc, &fops_registers);
 
-       sc->debug.debugfs_beacon = debugfs_create_file("beacon", S_IWUSR | S_IRUGO,
+       sc->debug.debugfs_beacon = debugfs_create_file("beacon",
+                               S_IWUSR | S_IRUSR,
                                sc->debug.debugfs_phydir, sc, &fops_beacon);
 
        sc->debug.debugfs_reset = debugfs_create_file("reset", S_IWUSR,
index a876ca8..2075ba9 100644 (file)
@@ -1085,8 +1085,7 @@ int ath5k_hw_channel(struct ath5k_hw *ah, struct ieee80211_channel *channel)
                                AR5K_PHY_CCKTXCTL_WORLD);
        }
 
-       ah->ah_current_channel.center_freq = channel->center_freq;
-       ah->ah_current_channel.hw_value = channel->hw_value;
+       ah->ah_current_channel = channel;
        ah->ah_turbo = channel->hw_value == CHANNEL_T ? true : false;
 
        return 0;
@@ -1731,7 +1730,7 @@ ath5k_hw_set_fast_div(struct ath5k_hw *ah, u8 ee_mode, bool enable)
 void
 ath5k_hw_set_antenna_mode(struct ath5k_hw *ah, u8 ant_mode)
 {
-       struct ieee80211_channel *channel = &ah->ah_current_channel;
+       struct ieee80211_channel *channel = ah->ah_current_channel;
        bool use_def_for_tx, update_def_on_tx, use_def_for_rts, fast_div;
        bool use_def_for_sg;
        u8 def_ant, tx_ant, ee_mode;
@@ -3011,7 +3010,7 @@ ath5k_hw_txpower(struct ath5k_hw *ah, struct ieee80211_channel *channel,
 int ath5k_hw_set_txpower_limit(struct ath5k_hw *ah, u8 txpower)
 {
        /*Just a try M.F.*/
-       struct ieee80211_channel *channel = &ah->ah_current_channel;
+       struct ieee80211_channel *channel = ah->ah_current_channel;
        u8 ee_mode;
 
        ATH5K_TRACE(ah->ah_sc);
index 73407b3..6d5aaf0 100644 (file)
@@ -411,7 +411,6 @@ int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue)
                        AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
                                AR5K_QCU_MISC_FRSHED_BCN_SENT_GT |
                                AR5K_QCU_MISC_CBREXP_DIS |
-                               AR5K_QCU_MISC_RDY_VEOL_POLICY |
                                AR5K_QCU_MISC_CBREXP_BCN_DIS);
 
                        ath5k_hw_reg_write(ah, ((AR5K_TUNE_BEACON_INTERVAL -
index bd0a97a..86733fd 100644 (file)
@@ -290,7 +290,6 @@ int ath5k_hw_set_power(struct ath5k_hw *ah, enum ath5k_power_mode mode,
        }
 
 commit:
-       ah->ah_power_mode = mode;
        ath5k_hw_reg_write(ah, staid, AR5K_STA_ID1);
 
        return 0;
index 5efc934..eb9d522 100644 (file)
@@ -272,7 +272,6 @@ struct ath_atx_tid {
        int sched;
        int paused;
        u8 state;
-       int addba_exchangeattempts;
 };
 
 struct ath_atx_ac {
@@ -541,6 +540,7 @@ struct ath_softc {
        int irq;
        spinlock_t sc_resetlock;
        spinlock_t sc_serial_rw;
+       spinlock_t ani_lock;
        struct mutex mutex;
 
        u8 curbssid[ETH_ALEN];
index 3639a2e..45c4ea5 100644 (file)
@@ -674,13 +674,6 @@ static void ath_beacon_config_adhoc(struct ath_softc *sc,
 
        intval = conf->beacon_interval & ATH9K_BEACON_PERIOD;
 
-       /*
-        * It looks like mac80211 may end up using beacon interval of zero in
-        * some cases (at least for mesh point). Avoid getting into an
-        * infinite loop by using a bit safer value instead..
-        */
-       if (intval == 0)
-               intval = 100;
 
        /* Pull nexttbtt forward to reflect the current TSF */
 
@@ -745,6 +738,14 @@ void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif)
                iftype = sc->sc_ah->opmode;
        }
 
+       /*
+        * It looks like mac80211 may end up using beacon interval of zero in
+        * some cases (at least for mesh point). Avoid getting into an
+        * infinite loop by using a bit safer value instead. To be safe,
+        * do sanity check on beacon interval for all operating modes.
+        */
+       if (cur_conf->beacon_interval == 0)
+               cur_conf->beacon_interval = 100;
 
        switch (iftype) {
        case NL80211_IFTYPE_AP:
index 6d20725..9f99f00 100644 (file)
@@ -500,31 +500,31 @@ int ath9k_init_debug(struct ath_softc *sc)
                goto err;
 
        sc->debug.debugfs_debug = debugfs_create_file("debug",
-               S_IRUGO | S_IWUSR, sc->debug.debugfs_phy, sc, &fops_debug);
+               S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, sc, &fops_debug);
        if (!sc->debug.debugfs_debug)
                goto err;
 
-       sc->debug.debugfs_dma = debugfs_create_file("dma", S_IRUGO,
+       sc->debug.debugfs_dma = debugfs_create_file("dma", S_IRUSR,
                                       sc->debug.debugfs_phy, sc, &fops_dma);
        if (!sc->debug.debugfs_dma)
                goto err;
 
        sc->debug.debugfs_interrupt = debugfs_create_file("interrupt",
-                                                    S_IRUGO,
+                                                    S_IRUSR,
                                                     sc->debug.debugfs_phy,
                                                     sc, &fops_interrupt);
        if (!sc->debug.debugfs_interrupt)
                goto err;
 
        sc->debug.debugfs_rcstat = debugfs_create_file("rcstat",
-                                                 S_IRUGO,
+                                                 S_IRUSR,
                                                  sc->debug.debugfs_phy,
                                                  sc, &fops_rcstat);
        if (!sc->debug.debugfs_rcstat)
                goto err;
 
        sc->debug.debugfs_wiphy = debugfs_create_file(
-               "wiphy", S_IRUGO | S_IWUSR, sc->debug.debugfs_phy, sc,
+               "wiphy", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, sc,
                &fops_wiphy);
        if (!sc->debug.debugfs_wiphy)
                goto err;
index a2fda70..d82a0f9 100644 (file)
@@ -2516,10 +2516,8 @@ static void ath9k_hw_set_def_power_per_rate_table(struct ath_hw *ah,
                        targetPowerCck.tPow2x[1];
                ratesArray[rate5_5s] = ratesArray[rate5_5l] =
                        targetPowerCck.tPow2x[2];
-               ;
                ratesArray[rate11s] = ratesArray[rate11l] =
                        targetPowerCck.tPow2x[3];
-               ;
        }
        if (IS_CHAN_HT40(chan)) {
                for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) {
index 34935a8..cffb078 100644 (file)
@@ -2345,7 +2345,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
        ath9k_hw_init_bb(ah, chan);
 
        if (!ath9k_hw_init_cal(ah, chan))
-               return -EIO;;
+               return -EIO;
 
        rx_chainmask = ah->rxchainmask;
        if ((rx_chainmask == 0x5) || (rx_chainmask == 0x3)) {
index 66a6c1f..961b0ce 100644 (file)
@@ -342,6 +342,7 @@ static void ath_ani_calibrate(unsigned long data)
        * don't calibrate when we're scanning.
        * we are most likely not on our home channel.
        */
+       spin_lock(&sc->ani_lock);
        if (sc->sc_flags & SC_OP_SCANNING)
                goto set_timer;
 
@@ -405,6 +406,7 @@ static void ath_ani_calibrate(unsigned long data)
        ath9k_ps_restore(sc);
 
 set_timer:
+       spin_unlock(&sc->ani_lock);
        /*
        * Set timer interval based on previous results.
        * The interval must be the shortest necessary to satisfy ANI,
@@ -887,6 +889,7 @@ static void setup_ht_cap(struct ath_softc *sc,
 {
 #define        ATH9K_HT_CAP_MAXRXAMPDU_65536 0x3       /* 2 ^ 16 */
 #define        ATH9K_HT_CAP_MPDUDENSITY_8 0x6          /* 8 usec */
+       u8 tx_streams, rx_streams;
 
        ht_info->ht_supported = true;
        ht_info->cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
@@ -899,45 +902,43 @@ static void setup_ht_cap(struct ath_softc *sc,
 
        /* set up supported mcs set */
        memset(&ht_info->mcs, 0, sizeof(ht_info->mcs));
+       tx_streams = !(sc->tx_chainmask & (sc->tx_chainmask - 1)) ? 1 : 2;
+       rx_streams = !(sc->rx_chainmask & (sc->rx_chainmask - 1)) ? 1 : 2;
 
-       switch(sc->rx_chainmask) {
-       case 1:
-               ht_info->mcs.rx_mask[0] = 0xff;
-               break;
-       case 3:
-       case 5:
-       case 7:
-       default:
-               ht_info->mcs.rx_mask[0] = 0xff;
-               ht_info->mcs.rx_mask[1] = 0xff;
-               break;
+       if (tx_streams != rx_streams) {
+               DPRINTF(sc, ATH_DBG_CONFIG, "TX streams %d, RX streams: %d\n",
+                       tx_streams, rx_streams);
+               ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_RX_DIFF;
+               ht_info->mcs.tx_params |= ((tx_streams - 1) <<
+                               IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT);
        }
 
-       ht_info->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
+       ht_info->mcs.rx_mask[0] = 0xff;
+       if (rx_streams >= 2)
+               ht_info->mcs.rx_mask[1] = 0xff;
+
+       ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_DEFINED;
 }
 
 static void ath9k_bss_assoc_info(struct ath_softc *sc,
                                 struct ieee80211_vif *vif,
                                 struct ieee80211_bss_conf *bss_conf)
 {
-       struct ath_vif *avp = (void *)vif->drv_priv;
 
        if (bss_conf->assoc) {
                DPRINTF(sc, ATH_DBG_CONFIG, "Bss Info ASSOC %d, bssid: %pM\n",
                        bss_conf->aid, sc->curbssid);
 
                /* New association, store aid */
-               if (avp->av_opmode == NL80211_IFTYPE_STATION) {
-                       sc->curaid = bss_conf->aid;
-                       ath9k_hw_write_associd(sc);
+               sc->curaid = bss_conf->aid;
+               ath9k_hw_write_associd(sc);
 
-                       /*
-                        * Request a re-configuration of Beacon related timers
-                        * on the receipt of the first Beacon frame (i.e.,
-                        * after time sync with the AP).
-                        */
-                       sc->sc_flags |= SC_OP_BEACON_SYNC;
-               }
+               /*
+                * Request a re-configuration of Beacon related timers
+                * on the receipt of the first Beacon frame (i.e.,
+                * after time sync with the AP).
+                */
+               sc->sc_flags |= SC_OP_BEACON_SYNC;
 
                /* Configure the beacon */
                ath_beacon_config(sc, vif);
@@ -952,6 +953,8 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc,
        } else {
                DPRINTF(sc, ATH_DBG_CONFIG, "Bss Info DISASSOC\n");
                sc->curaid = 0;
+               /* Stop ANI */
+               del_timer_sync(&sc->ani.timer);
        }
 }
 
@@ -1311,6 +1314,7 @@ static int ath_init(u16 devid, struct ath_softc *sc)
        spin_lock_init(&sc->wiphy_lock);
        spin_lock_init(&sc->sc_resetlock);
        spin_lock_init(&sc->sc_serial_rw);
+       spin_lock_init(&sc->ani_lock);
        mutex_init(&sc->mutex);
        tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc);
        tasklet_init(&sc->bcon_tasklet, ath_beacon_tasklet,
@@ -2196,7 +2200,9 @@ static int ath9k_add_interface(struct ieee80211_hw *hw,
 
        ath9k_hw_set_interrupts(sc->sc_ah, sc->imask);
 
-       if (conf->type == NL80211_IFTYPE_AP)
+       if (conf->type == NL80211_IFTYPE_AP    ||
+           conf->type == NL80211_IFTYPE_ADHOC ||
+           conf->type == NL80211_IFTYPE_MONITOR)
                ath_start_ani(sc);
 
 out:
@@ -2681,9 +2687,9 @@ static void ath9k_sw_scan_start(struct ieee80211_hw *hw)
        aphy->state = ATH_WIPHY_SCAN;
        ath9k_wiphy_pause_all_forced(sc, aphy);
 
-       mutex_lock(&sc->mutex);
+       spin_lock_bh(&sc->ani_lock);
        sc->sc_flags |= SC_OP_SCANNING;
-       mutex_unlock(&sc->mutex);
+       spin_unlock_bh(&sc->ani_lock);
 }
 
 static void ath9k_sw_scan_complete(struct ieee80211_hw *hw)
@@ -2691,11 +2697,11 @@ 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);
+       spin_lock_bh(&sc->ani_lock);
        aphy->state = ATH_WIPHY_ACTIVE;
        sc->sc_flags &= ~SC_OP_SCANNING;
        sc->sc_flags |= SC_OP_FULL_RESET;
-       mutex_unlock(&sc->mutex);
+       spin_unlock_bh(&sc->ani_lock);
 }
 
 struct ieee80211_ops ath9k_ops = {
index cece1c4..b3da81d 100644 (file)
@@ -236,10 +236,31 @@ static int ath_rx_prepare(struct sk_buff *skb, struct ath_desc *ds,
        rx_status->signal = rx_status->noise + ds->ds_rxstat.rs_rssi;
        rx_status->antenna = ds->ds_rxstat.rs_antenna;
 
-       /* at 45 you will be able to use MCS 15 reliably. A more elaborate
-        * scheme can be used here but it requires tables of SNR/throughput for
-        * each possible mode used. */
-       rx_status->qual =  ds->ds_rxstat.rs_rssi * 100 / 45;
+       /*
+        * Theory for reporting quality:
+        *
+        * At a hardware RSSI of 45 you will be able to use MCS 7  reliably.
+        * At a hardware RSSI of 45 you will be able to use MCS 15 reliably.
+        * At a hardware RSSI of 35 you should be able use 54 Mbps reliably.
+        *
+        * MCS 7  is the highets MCS index usable by a 1-stream device.
+        * MCS 15 is the highest MCS index usable by a 2-stream device.
+        *
+        * All ath9k devices are either 1-stream or 2-stream.
+        *
+        * How many bars you see is derived from the qual reporting.
+        *
+        * A more elaborate scheme can be used here but it requires tables
+        * of SNR/throughput for each possible mode used. For the MCS table
+        * you can refer to the wireless wiki:
+        *
+        * http://wireless.kernel.org/en/developers/Documentation/ieee80211/802.11n
+        *
+        */
+       if (conf_is_ht(&hw->conf))
+               rx_status->qual =  ds->ds_rxstat.rs_rssi * 100 / 45;
+       else
+               rx_status->qual =  ds->ds_rxstat.rs_rssi * 100 / 35;
 
        /* rssi can be more than 45 though, anything above that
         * should be considered at 100% */
@@ -505,11 +526,6 @@ static bool ath_beacon_dtim_pending_cab(struct sk_buff *skb)
        return false;
 }
 
-static void ath_rx_ps_back_to_sleep(struct ath_softc *sc)
-{
-       sc->sc_flags &= ~(SC_OP_WAIT_FOR_BEACON | SC_OP_WAIT_FOR_CAB);
-}
-
 static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb)
 {
        struct ieee80211_mgmt *mgmt;
@@ -521,6 +537,8 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb)
        if (memcmp(sc->curbssid, mgmt->bssid, ETH_ALEN) != 0)
                return; /* not from our current AP */
 
+       sc->sc_flags &= ~SC_OP_WAIT_FOR_BEACON;
+
        if (sc->sc_flags & SC_OP_BEACON_SYNC) {
                sc->sc_flags &= ~SC_OP_BEACON_SYNC;
                DPRINTF(sc, ATH_DBG_PS, "Reconfigure Beacon timers based on "
@@ -528,14 +546,6 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb)
                ath_beacon_config(sc, NULL);
        }
 
-       if (!(sc->hw->conf.flags & IEEE80211_CONF_PS)) {
-               /* We are not in PS mode anymore; remain awake */
-               DPRINTF(sc, ATH_DBG_PS, "Not in PS mode anymore, remain "
-                       "awake\n");
-               sc->sc_flags &= ~(SC_OP_WAIT_FOR_BEACON | SC_OP_WAIT_FOR_CAB);
-               return;
-       }
-
        if (ath_beacon_dtim_pending_cab(skb)) {
                /*
                 * Remain awake waiting for buffered broadcast/multicast
@@ -556,11 +566,9 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb)
                 * fails to send a frame indicating that all CAB frames have
                 * been delivered.
                 */
+               sc->sc_flags &= ~SC_OP_WAIT_FOR_CAB;
                DPRINTF(sc, ATH_DBG_PS, "PS wait for CAB frames timed out\n");
        }
-
-       /* No more broadcast/multicast frames to be received at this point. */
-       ath_rx_ps_back_to_sleep(sc);
 }
 
 static void ath_rx_ps(struct ath_softc *sc, struct sk_buff *skb)
@@ -578,13 +586,13 @@ static void ath_rx_ps(struct ath_softc *sc, struct sk_buff *skb)
                  ieee80211_is_action(hdr->frame_control)) &&
                 is_multicast_ether_addr(hdr->addr1) &&
                 !ieee80211_has_moredata(hdr->frame_control)) {
-               DPRINTF(sc, ATH_DBG_PS, "All PS CAB frames received, back to "
-                       "sleep\n");
                /*
                 * No more broadcast/multicast frames to be received at this
                 * point.
                 */
-               ath_rx_ps_back_to_sleep(sc);
+               sc->sc_flags &= ~SC_OP_WAIT_FOR_CAB;
+               DPRINTF(sc, ATH_DBG_PS, "All PS CAB frames received, back to "
+                       "sleep\n");
        } else if ((sc->sc_flags & SC_OP_WAIT_FOR_PSPOLL_DATA) &&
                   !is_multicast_ether_addr(hdr->addr1) &&
                   !ieee80211_has_morefrags(hdr->frame_control)) {
@@ -619,13 +627,18 @@ static void ath_rx_send_to_mac80211(struct ath_softc *sc, struct sk_buff *skb,
                        if (aphy == NULL)
                                continue;
                        nskb = skb_copy(skb, GFP_ATOMIC);
-                       if (nskb)
-                               __ieee80211_rx(aphy->hw, nskb, rx_status);
+                       if (nskb) {
+                               memcpy(IEEE80211_SKB_RXCB(nskb), rx_status,
+                                       sizeof(*rx_status));
+                               ieee80211_rx(aphy->hw, nskb);
+                       }
                }
-               __ieee80211_rx(sc->hw, skb, rx_status);
+               memcpy(IEEE80211_SKB_RXCB(skb), rx_status, sizeof(*rx_status));
+               ieee80211_rx(sc->hw, skb);
        } else {
                /* Deliver unicast frames based on receiver address */
-               __ieee80211_rx(ath_get_virt_hw(sc, hdr), skb, rx_status);
+               memcpy(IEEE80211_SKB_RXCB(skb), rx_status, sizeof(*rx_status));
+               ieee80211_rx(ath_get_virt_hw(sc, hdr), skb);
        }
 }
 
index 4ccf48e..5de9878 100644 (file)
@@ -73,18 +73,6 @@ static void ath_tx_rc_status(struct ath_buf *bf, struct ath_desc *ds,
 /* Aggregation logic */
 /*********************/
 
-static int ath_aggr_query(struct ath_softc *sc, struct ath_node *an, u8 tidno)
-{
-       struct ath_atx_tid *tid;
-       tid = ATH_AN_2_TID(an, tidno);
-
-       if (tid->state & AGGR_ADDBA_COMPLETE ||
-           tid->state & AGGR_ADDBA_PROGRESS)
-               return 1;
-       else
-               return 0;
-}
-
 static void ath_tx_queue_tid(struct ath_txq *txq, struct ath_atx_tid *tid)
 {
        struct ath_atx_ac *ac = tid->ac;
@@ -250,6 +238,10 @@ static struct ath_buf* ath_clone_txbuf(struct ath_softc *sc, struct ath_buf *bf)
        struct ath_buf *tbf;
 
        spin_lock_bh(&sc->tx.txbuflock);
+       if (WARN_ON(list_empty(&sc->tx.txbuf))) {
+               spin_unlock_bh(&sc->tx.txbuflock);
+               return NULL;
+       }
        ASSERT(!list_empty((&sc->tx.txbuf)));
        tbf = list_first_entry(&sc->tx.txbuf, struct ath_buf, list);
        list_del(&tbf->list);
@@ -391,6 +383,8 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
                                struct ath_buf *tbf;
 
                                tbf = ath_clone_txbuf(sc, bf_last);
+                               if (!tbf)
+                                       break;
                                ath9k_hw_cleartxdesc(sc->sc_ah, tbf->bf_desc);
                                list_add_tail(&tbf->list, &bf_head);
                        } else {
@@ -414,7 +408,6 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
        if (tid->state & AGGR_CLEANUP) {
                if (tid->baw_head == tid->baw_tail) {
                        tid->state &= ~AGGR_ADDBA_COMPLETE;
-                       tid->addba_exchangeattempts = 0;
                        tid->state &= ~AGGR_CLEANUP;
 
                        /* send buffered frames as singles */
@@ -719,7 +712,6 @@ int ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
 
        if (!(txtid->state & AGGR_ADDBA_COMPLETE)) {
                txtid->state &= ~AGGR_ADDBA_PROGRESS;
-               txtid->addba_exchangeattempts = 0;
                return 0;
        }
 
@@ -747,7 +739,6 @@ int ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
                txtid->state |= AGGR_CLEANUP;
        } else {
                txtid->state &= ~AGGR_ADDBA_COMPLETE;
-               txtid->addba_exchangeattempts = 0;
                ath_tx_flush_tid(sc, txtid);
        }
 
@@ -780,14 +771,8 @@ bool ath_tx_aggr_check(struct ath_softc *sc, struct ath_node *an, u8 tidno)
 
        txtid = ATH_AN_2_TID(an, tidno);
 
-       if (!(txtid->state & AGGR_ADDBA_COMPLETE)) {
-               if (!(txtid->state & AGGR_ADDBA_PROGRESS) &&
-                   (txtid->addba_exchangeattempts < ADDBA_EXCHANGE_ATTEMPTS)) {
-                       txtid->addba_exchangeattempts++;
+       if (!(txtid->state & (AGGR_ADDBA_COMPLETE | AGGR_ADDBA_PROGRESS)))
                        return true;
-               }
-       }
-
        return false;
 }
 
@@ -1636,7 +1621,7 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf,
                        goto tx_done;
                }
 
-               if (ath_aggr_query(sc, an, bf->bf_tidno)) {
+               if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) {
                        /*
                         * Try aggregation if it's a unicast data frame
                         * and the destination is HT capable.
@@ -2122,7 +2107,6 @@ void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an)
                tid->ac = &an->ac[acno];
                tid->state &= ~AGGR_ADDBA_COMPLETE;
                tid->state &= ~AGGR_ADDBA_PROGRESS;
-               tid->addba_exchangeattempts = 0;
        }
 
        for (acno = 0, ac = &an->ac[acno];
@@ -2179,7 +2163,6 @@ void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an)
                                        tid->sched = false;
                                        ath_tid_drain(sc, txq, tid);
                                        tid->state &= ~AGGR_ADDBA_COMPLETE;
-                                       tid->addba_exchangeattempts = 0;
                                        tid->state &= ~AGGR_CLEANUP;
                                }
                        }
index bf3d25b..077bcc1 100644 (file)
@@ -586,7 +586,5 @@ u32 ath_regd_get_band_ctl(struct ath_regulatory *reg,
        default:
                return NO_CTL;
        }
-
-       return NO_CTL;
 }
 EXPORT_SYMBOL(ath_regd_get_band_ctl);
index 291a94b..05813bc 100644 (file)
@@ -793,13 +793,13 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev)
            !(*priv->present_callback)(priv->card)) {
                dev->stats.tx_errors++;
                dev_kfree_skb(skb);
-               return 0;
+               return NETDEV_TX_OK;
        }
 
        if (priv->station_state != STATION_STATE_READY) {
                dev->stats.tx_errors++;
                dev_kfree_skb(skb);
-               return 0;
+               return NETDEV_TX_OK;
        }
 
        /* first ensure the timer func cannot run */
@@ -856,7 +856,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev)
        spin_unlock_bh(&priv->timerlock);
        dev_kfree_skb(skb);
 
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 static void atmel_transmit_management_frame(struct atmel_private *priv,
index 55f36a7..5b85e7d 100644 (file)
@@ -670,7 +670,8 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr)
                goto drop;
        }
 
-       ieee80211_rx_irqsafe(dev->wl->hw, skb, &status);
+       memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status));
+       ieee80211_rx_irqsafe(dev->wl->hw, skb);
 
        return;
 drop:
index b8e39dd..f79cee8 100644 (file)
@@ -591,7 +591,8 @@ void b43legacy_rx(struct b43legacy_wldev *dev,
        }
 
        dev->stats.last_rx = jiffies;
-       ieee80211_rx_irqsafe(dev->wl->hw, skb, &status);
+       memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status));
+       ieee80211_rx_irqsafe(dev->wl->hw, skb);
 
        return;
 drop:
index d313b00..1fe1bba 100644 (file)
@@ -75,7 +75,7 @@ int hostap_data_start_xmit(struct sk_buff *skb, struct net_device *dev)
                printk(KERN_DEBUG "%s: hostap_data_start_xmit: short skb "
                       "(len=%d)\n", dev->name, skb->len);
                kfree_skb(skb);
-               return 0;
+               return NETDEV_TX_OK;
        }
 
        if (local->ddev != dev) {
@@ -89,14 +89,14 @@ int hostap_data_start_xmit(struct sk_buff *skb, struct net_device *dev)
                        printk(KERN_DEBUG "%s: prism2_tx: trying to use "
                               "AP device with Ethernet net dev\n", dev->name);
                        kfree_skb(skb);
-                       return 0;
+                       return NETDEV_TX_OK;
                }
        } else {
                if (local->iw_mode == IW_MODE_REPEAT) {
                        printk(KERN_DEBUG "%s: prism2_tx: trying to use "
                               "non-WDS link in Repeater mode\n", dev->name);
                        kfree_skb(skb);
-                       return 0;
+                       return NETDEV_TX_OK;
                } else if (local->iw_mode == IW_MODE_INFRA &&
                           (local->wds_type & HOSTAP_WDS_AP_CLIENT) &&
                           memcmp(skb->data + ETH_ALEN, dev->dev_addr,
@@ -210,13 +210,13 @@ int hostap_data_start_xmit(struct sk_buff *skb, struct net_device *dev)
                skb = skb_unshare(skb, GFP_ATOMIC);
                if (skb == NULL) {
                        iface->stats.tx_dropped++;
-                       return 0;
+                       return NETDEV_TX_OK;
                }
                if (pskb_expand_head(skb, need_headroom, need_tailroom,
                                     GFP_ATOMIC)) {
                        kfree_skb(skb);
                        iface->stats.tx_dropped++;
-                       return 0;
+                       return NETDEV_TX_OK;
                }
        } else if (skb_headroom(skb) < need_headroom) {
                struct sk_buff *tmp = skb;
@@ -224,13 +224,13 @@ int hostap_data_start_xmit(struct sk_buff *skb, struct net_device *dev)
                kfree_skb(tmp);
                if (skb == NULL) {
                        iface->stats.tx_dropped++;
-                       return 0;
+                       return NETDEV_TX_OK;
                }
        } else {
                skb = skb_unshare(skb, GFP_ATOMIC);
                if (skb == NULL) {
                        iface->stats.tx_dropped++;
-                       return 0;
+                       return NETDEV_TX_OK;
                }
        }
 
@@ -256,7 +256,7 @@ int hostap_data_start_xmit(struct sk_buff *skb, struct net_device *dev)
        /* Send IEEE 802.11 encapsulated frame using the master radio device */
        skb->dev = local->dev;
        dev_queue_xmit(skb);
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 
@@ -276,7 +276,7 @@ int hostap_mgmt_start_xmit(struct sk_buff *skb, struct net_device *dev)
                printk(KERN_DEBUG "%s: hostap_mgmt_start_xmit: short skb "
                       "(len=%d)\n", dev->name, skb->len);
                kfree_skb(skb);
-               return 0;
+               return NETDEV_TX_OK;
        }
 
        iface->stats.tx_packets++;
@@ -301,7 +301,7 @@ int hostap_mgmt_start_xmit(struct sk_buff *skb, struct net_device *dev)
        /* Send IEEE 802.11 encapsulated frame using the master radio device */
        skb->dev = local->dev;
        dev_queue_xmit(skb);
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 
@@ -396,7 +396,7 @@ int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev)
                printk(KERN_DEBUG "%s: invalid skb->cb magic (0x%08x, "
                       "expected 0x%08x)\n",
                       dev->name, meta->magic, HOSTAP_SKB_TX_DATA_MAGIC);
-               ret = 0;
+               ret = NETDEV_TX_OK;
                iface->stats.tx_dropped++;
                goto fail;
        }
@@ -414,7 +414,7 @@ int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev)
        if (skb->len < 24) {
                printk(KERN_DEBUG "%s: hostap_master_start_xmit: short skb "
                       "(len=%d)\n", dev->name, skb->len);
-               ret = 0;
+               ret = NETDEV_TX_OK;
                iface->stats.tx_dropped++;
                goto fail;
        }
@@ -441,13 +441,13 @@ int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev)
                               dev->name, meta->ethertype);
                        hostap_dump_tx_80211(dev->name, skb);
 
-                       ret = 0; /* drop packet */
+                       ret = NETDEV_TX_OK; /* drop packet */
                        iface->stats.tx_dropped++;
                        goto fail;
                }
                break;
        case AP_TX_DROP:
-               ret = 0; /* drop packet */
+               ret = NETDEV_TX_OK; /* drop packet */
                iface->stats.tx_dropped++;
                goto fail;
        case AP_TX_RETRY:
@@ -455,7 +455,7 @@ int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev)
        case AP_TX_BUFFERED:
                /* do not free skb here, it will be freed when the
                 * buffered frame is sent/timed out */
-               ret = 0;
+               ret = NETDEV_TX_OK;
                goto tx_exit;
        }
 
@@ -501,7 +501,7 @@ int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev)
                               "frame (drop_unencrypted=1)\n", dev->name);
                }
                iface->stats.tx_dropped++;
-               ret = 0;
+               ret = NETDEV_TX_OK;
                goto fail;
        }
 
@@ -510,7 +510,7 @@ int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev)
                if (skb == NULL) {
                        printk(KERN_DEBUG "%s: TX - encryption failed\n",
                               dev->name);
-                       ret = 0;
+                       ret = NETDEV_TX_OK;
                        goto fail;
                }
                meta = (struct hostap_skb_tx_data *) skb->cb;
@@ -519,23 +519,23 @@ int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev)
                               "expected 0x%08x) after hostap_tx_encrypt\n",
                               dev->name, meta->magic,
                               HOSTAP_SKB_TX_DATA_MAGIC);
-                       ret = 0;
+                       ret = NETDEV_TX_OK;
                        iface->stats.tx_dropped++;
                        goto fail;
                }
        }
 
        if (local->func->tx == NULL || local->func->tx(skb, dev)) {
-               ret = 0;
+               ret = NETDEV_TX_OK;
                iface->stats.tx_dropped++;
        } else {
-               ret = 0;
+               ret = NETDEV_TX_OK;
                iface->stats.tx_packets++;
                iface->stats.tx_bytes += skb->len;
        }
 
  fail:
-       if (!ret && skb)
+       if (ret == NETDEV_TX_OK && skb)
                dev_kfree_skb(skb);
  tx_exit:
        if (tx.sta_ptr)
index 44c29b3..d726b3c 100644 (file)
@@ -11436,11 +11436,11 @@ static struct pci_device_id card_ids[] = {
        {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2754, 0, 0, 0},
        {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2761, 0, 0, 0},
        {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2762, 0, 0, 0},
-       {PCI_VENDOR_ID_INTEL, 0x104f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-       {PCI_VENDOR_ID_INTEL, 0x4220, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, /* BG */
-       {PCI_VENDOR_ID_INTEL, 0x4221, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, /* BG */
-       {PCI_VENDOR_ID_INTEL, 0x4223, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, /* ABG */
-       {PCI_VENDOR_ID_INTEL, 0x4224, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, /* ABG */
+       {PCI_VDEVICE(INTEL, 0x104f), 0},
+       {PCI_VDEVICE(INTEL, 0x4220), 0},        /* BG */
+       {PCI_VDEVICE(INTEL, 0x4221), 0},        /* BG */
+       {PCI_VDEVICE(INTEL, 0x4223), 0},        /* ABG */
+       {PCI_VDEVICE(INTEL, 0x4224), 0},        /* ABG */
 
        /* required last entry */
        {0,}
index da2ad54..2e8f84f 100644 (file)
@@ -527,13 +527,13 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
                if (ret == 0) {
                        dev->stats.tx_packets++;
                        dev->stats.tx_bytes += txb->payload_size;
-                       return 0;
+                       return NETDEV_TX_OK;
                }
 
                ieee80211_txb_free(txb);
        }
 
-       return 0;
+       return NETDEV_TX_OK;
 
       failed:
        spin_unlock_irqrestore(&ieee->lock, flags);
index 46288e7..b0246db 100644 (file)
@@ -577,7 +577,8 @@ static void iwl3945_pass_packet_to_mac80211(struct iwl_priv *priv,
        if (ieee80211_is_data(hdr->frame_control))
                priv->rxtxpackets += len;
 #endif
-       ieee80211_rx_irqsafe(priv->hw, rxb->skb, stats);
+       memcpy(IEEE80211_SKB_RXCB(rxb->skb), stats, sizeof(*stats));
+       ieee80211_rx_irqsafe(priv->hw, rxb->skb);
        rxb->skb = NULL;
 }
 
@@ -1986,7 +1987,7 @@ 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);
+       iwl_set_rxon_hwcrypto(priv, !iwl3945_mod_params.sw_crypto);
 
        /* Apply the new configuration */
        rc = iwl_send_cmd_pdu(priv, REPLY_RXON,
@@ -2562,6 +2563,7 @@ int iwl3945_hw_set_hw_params(struct iwl_priv *priv)
        priv->hw_params.bcast_sta_id = IWL3945_BROADCAST_ID;
 
        priv->hw_params.rx_wrt_ptr_reg = FH39_RSCSR_CHNL0_WPTR;
+       priv->hw_params.max_beacon_itrvl = IWL39_MAX_UCODE_BEACON_INTERVAL;
 
        return 0;
 }
index 8f3d4bc..edbb0bf 100644 (file)
@@ -728,7 +728,7 @@ static int iwl4965_alive_notify(struct iwl_priv *priv)
 
 static struct iwl_sensitivity_ranges iwl4965_sensitivity = {
        .min_nrg_cck = 97,
-       .max_nrg_cck = 0,
+       .max_nrg_cck = 0, /* not used, set to 0 */
 
        .auto_corr_min_ofdm = 85,
        .auto_corr_min_ofdm_mrc = 170,
index b3c648c..85e8bac 100644 (file)
@@ -388,7 +388,7 @@ void iwl5000_rts_tx_cmd_flag(struct ieee80211_tx_info *info,
 
 static struct iwl_sensitivity_ranges iwl5000_sensitivity = {
        .min_nrg_cck = 95,
-       .max_nrg_cck = 0,
+       .max_nrg_cck = 0, /* not used, set to 0 */
        .auto_corr_min_ofdm = 90,
        .auto_corr_min_ofdm_mrc = 170,
        .auto_corr_min_ofdm_x1 = 120,
@@ -407,6 +407,28 @@ static struct iwl_sensitivity_ranges iwl5000_sensitivity = {
        .nrg_th_ofdm = 95,
 };
 
+static struct iwl_sensitivity_ranges iwl5150_sensitivity = {
+       .min_nrg_cck = 95,
+       .max_nrg_cck = 0, /* not used, set to 0 */
+       .auto_corr_min_ofdm = 90,
+       .auto_corr_min_ofdm_mrc = 170,
+       .auto_corr_min_ofdm_x1 = 105,
+       .auto_corr_min_ofdm_mrc_x1 = 220,
+
+       .auto_corr_max_ofdm = 120,
+       .auto_corr_max_ofdm_mrc = 210,
+       /* max = min for performance bug in 5150 DSP */
+       .auto_corr_max_ofdm_x1 = 105,
+       .auto_corr_max_ofdm_mrc_x1 = 220,
+
+       .auto_corr_min_cck = 125,
+       .auto_corr_max_cck = 200,
+       .auto_corr_min_cck_mrc = 170,
+       .auto_corr_max_cck_mrc = 400,
+       .nrg_th_cck = 95,
+       .nrg_th_ofdm = 95,
+};
+
 static const u8 *iwl5000_eeprom_query_addr(const struct iwl_priv *priv,
                                           size_t offset)
 {
@@ -826,8 +848,6 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv)
                                        BIT(IEEE80211_BAND_5GHZ);
        priv->hw_params.rx_wrt_ptr_reg = FH_RSCSR_CHNL0_WPTR;
 
-       priv->hw_params.sens = &iwl5000_sensitivity;
-
        priv->hw_params.tx_chains_num = num_of_ant(priv->cfg->valid_tx_ant);
        priv->hw_params.rx_chains_num = num_of_ant(priv->cfg->valid_rx_ant);
        priv->hw_params.valid_tx_ant = priv->cfg->valid_tx_ant;
@@ -836,9 +856,11 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv)
        if (priv->cfg->ops->lib->temp_ops.set_ct_kill)
                priv->cfg->ops->lib->temp_ops.set_ct_kill(priv);
 
+       /* Set initial sensitivity parameters */
        /* Set initial calibration set */
        switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) {
        case CSR_HW_REV_TYPE_5150:
+               priv->hw_params.sens = &iwl5150_sensitivity;
                priv->hw_params.calib_init_cfg =
                        BIT(IWL_CALIB_DC)               |
                        BIT(IWL_CALIB_LO)               |
@@ -847,6 +869,7 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv)
 
                break;
        default:
+               priv->hw_params.sens = &iwl5000_sensitivity;
                priv->hw_params.calib_init_cfg =
                        BIT(IWL_CALIB_XTAL)             |
                        BIT(IWL_CALIB_LO)               |
index 355f50e..e2cc599 100644 (file)
@@ -171,7 +171,7 @@ int iwl_commit_rxon(struct iwl_priv *priv)
                       le16_to_cpu(priv->staging_rxon.channel),
                       priv->staging_rxon.bssid_addr);
 
-       iwl_set_rxon_hwcrypto(priv, !priv->hw_params.sw_crypto);
+       iwl_set_rxon_hwcrypto(priv, !priv->cfg->mod_params->sw_crypto);
 
        /* Apply the new configuration
         * RXON unassoc clears the station table in uCode, send it before
@@ -512,70 +512,6 @@ int iwl_hw_tx_queue_init(struct iwl_priv *priv,
        return 0;
 }
 
-
-/******************************************************************************
- *
- * Misc. internal state and helper functions
- *
- ******************************************************************************/
-
-#define MAX_UCODE_BEACON_INTERVAL      4096
-
-static u16 iwl_adjust_beacon_interval(u16 beacon_val)
-{
-       u16 new_val = 0;
-       u16 beacon_factor = 0;
-
-       beacon_factor = (beacon_val + MAX_UCODE_BEACON_INTERVAL)
-                                       / MAX_UCODE_BEACON_INTERVAL;
-       new_val = beacon_val / beacon_factor;
-
-       if (!new_val)
-               new_val = MAX_UCODE_BEACON_INTERVAL;
-
-       return new_val;
-}
-
-static void iwl_setup_rxon_timing(struct iwl_priv *priv)
-{
-       u64 tsf;
-       s32 interval_tm, rem;
-       unsigned long flags;
-       struct ieee80211_conf *conf = NULL;
-       u16 beacon_int = 0;
-
-       conf = ieee80211_get_hw_conf(priv->hw);
-
-       spin_lock_irqsave(&priv->lock, flags);
-       priv->rxon_timing.timestamp = cpu_to_le64(priv->timestamp);
-       priv->rxon_timing.listen_interval = cpu_to_le16(conf->listen_interval);
-
-       if (priv->iw_mode == NL80211_IFTYPE_STATION) {
-               beacon_int = iwl_adjust_beacon_interval(priv->beacon_int);
-               priv->rxon_timing.atim_window = 0;
-       } else {
-               beacon_int = iwl_adjust_beacon_interval(
-                       priv->vif->bss_conf.beacon_int);
-
-               /* TODO: we need to get atim_window from upper stack
-                * for now we set to 0 */
-               priv->rxon_timing.atim_window = 0;
-       }
-
-       priv->rxon_timing.beacon_interval = cpu_to_le16(beacon_int);
-
-       tsf = priv->timestamp; /* tsf is modifed by do_div: copy it */
-       interval_tm = beacon_int * 1024;
-       rem = do_div(tsf, interval_tm);
-       priv->rxon_timing.beacon_init_val = cpu_to_le32(interval_tm - rem);
-
-       spin_unlock_irqrestore(&priv->lock, flags);
-       IWL_DEBUG_ASSOC(priv, "beacon interval %d beacon timer %d beacon tim %d\n",
-                       le16_to_cpu(priv->rxon_timing.beacon_interval),
-                       le32_to_cpu(priv->rxon_timing.beacon_init_val),
-                       le16_to_cpu(priv->rxon_timing.atim_window));
-}
-
 /******************************************************************************
  *
  * Generic RX handler implementations
@@ -1812,6 +1748,11 @@ static int iwl_prepare_card_hw(struct iwl_priv *priv)
 
        IWL_DEBUG_INFO(priv, "iwl_prepare_card_hw enter \n");
 
+       ret = iwl_set_hw_ready(priv);
+       if (priv->hw_ready)
+               return ret;
+
+       /* If HW is not ready, prepare the conditions to check again */
        iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG,
                        CSR_HW_IF_CONFIG_REG_PREPARE);
 
@@ -1819,6 +1760,7 @@ static int iwl_prepare_card_hw(struct iwl_priv *priv)
                        ~CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE,
                        CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE, 150000);
 
+       /* HW should be ready by now, check again. */
        if (ret != -ETIMEDOUT)
                iwl_set_hw_ready(priv);
 
@@ -2331,7 +2273,7 @@ static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
 
        IWL_DEBUG_MAC80211(priv, "enter\n");
 
-       if (priv->hw_params.sw_crypto) {
+       if (priv->cfg->mod_params->sw_crypto) {
                IWL_DEBUG_MAC80211(priv, "leave - hwcrypto disabled\n");
                return -EOPNOTSUPP;
        }
index a5d6367..f8bf592 100644 (file)
@@ -251,12 +251,7 @@ static int iwl_sens_energy_cck(struct iwl_priv *priv,
 
                /* increase energy threshold (reduce nrg value)
                 *   to decrease sensitivity */
-               if (data->nrg_th_cck >
-                       (ranges->max_nrg_cck + NRG_STEP_CCK))
-                       data->nrg_th_cck = data->nrg_th_cck
-                                                - NRG_STEP_CCK;
-               else
-                       data->nrg_th_cck = ranges->max_nrg_cck;
+               data->nrg_th_cck = data->nrg_th_cck - NRG_STEP_CCK;
        /* Else if we got fewer than desired, increase sensitivity */
        } else if (false_alarms < min_false_alarms) {
                data->nrg_curr_state = IWL_FA_TOO_FEW;
index c87033b..ebb2fbc 100644 (file)
@@ -765,6 +765,8 @@ struct iwl5000_rxon_assoc_cmd {
 } __attribute__ ((packed));
 
 #define IWL_CONN_MAX_LISTEN_INTERVAL   10
+#define IWL_MAX_UCODE_BEACON_INTERVAL  4 /* 4096 */
+#define IWL39_MAX_UCODE_BEACON_INTERVAL        1 /* 1024 */
 
 /*
  * REPLY_RXON_TIMING = 0x14 (command, has simple generic response)
@@ -1922,7 +1924,7 @@ struct iwl_link_qual_general_params {
 #define LINK_QUAL_AGG_DISABLE_START_MIN        (0)
 
 #define LINK_QUAL_AGG_FRAME_LIMIT_DEF  (31)
-#define LINK_QUAL_AGG_FRAME_LIMIT_MAX  (64)
+#define LINK_QUAL_AGG_FRAME_LIMIT_MAX  (63)
 #define LINK_QUAL_AGG_FRAME_LIMIT_MIN  (0)
 
 /**
index 6ab0716..d5cd9a2 100644 (file)
@@ -635,6 +635,63 @@ u8 iwl_is_fat_tx_allowed(struct iwl_priv *priv,
 }
 EXPORT_SYMBOL(iwl_is_fat_tx_allowed);
 
+static u16 iwl_adjust_beacon_interval(u16 beacon_val, u16 max_beacon_val)
+{
+       u16 new_val = 0;
+       u16 beacon_factor = 0;
+
+       beacon_factor = (beacon_val + max_beacon_val) / max_beacon_val;
+       new_val = beacon_val / beacon_factor;
+
+       if (!new_val)
+               new_val = max_beacon_val;
+
+       return new_val;
+}
+
+void iwl_setup_rxon_timing(struct iwl_priv *priv)
+{
+       u64 tsf;
+       s32 interval_tm, rem;
+       unsigned long flags;
+       struct ieee80211_conf *conf = NULL;
+       u16 beacon_int;
+
+       conf = ieee80211_get_hw_conf(priv->hw);
+
+       spin_lock_irqsave(&priv->lock, flags);
+       priv->rxon_timing.timestamp = cpu_to_le64(priv->timestamp);
+       priv->rxon_timing.listen_interval = cpu_to_le16(conf->listen_interval);
+
+       if (priv->iw_mode == NL80211_IFTYPE_STATION) {
+               beacon_int = priv->beacon_int;
+               priv->rxon_timing.atim_window = 0;
+       } else {
+               beacon_int = priv->vif->bss_conf.beacon_int;
+
+               /* TODO: we need to get atim_window from upper stack
+                * for now we set to 0 */
+               priv->rxon_timing.atim_window = 0;
+       }
+
+       beacon_int = iwl_adjust_beacon_interval(beacon_int,
+                               priv->hw_params.max_beacon_itrvl * 1024);
+       priv->rxon_timing.beacon_interval = cpu_to_le16(beacon_int);
+
+       tsf = priv->timestamp; /* tsf is modifed by do_div: copy it */
+       interval_tm = beacon_int * 1024;
+       rem = do_div(tsf, interval_tm);
+       priv->rxon_timing.beacon_init_val = cpu_to_le32(interval_tm - rem);
+
+       spin_unlock_irqrestore(&priv->lock, flags);
+       IWL_DEBUG_ASSOC(priv,
+                       "beacon interval %d beacon timer %d beacon tim %d\n",
+                       le16_to_cpu(priv->rxon_timing.beacon_interval),
+                       le32_to_cpu(priv->rxon_timing.beacon_init_val),
+                       le16_to_cpu(priv->rxon_timing.atim_window));
+}
+EXPORT_SYMBOL(iwl_setup_rxon_timing);
+
 void iwl_set_rxon_hwcrypto(struct iwl_priv *priv, int hw_decrypt)
 {
        struct iwl_rxon_cmd *rxon = &priv->staging_rxon;
@@ -1325,7 +1382,8 @@ int iwl_setup_mac(struct iwl_priv *priv)
        hw->flags = IEEE80211_HW_SIGNAL_DBM |
                    IEEE80211_HW_NOISE_DBM |
                    IEEE80211_HW_AMPDU_AGGREGATION |
-                   IEEE80211_HW_SPECTRUM_MGMT;
+                   IEEE80211_HW_SPECTRUM_MGMT |
+                   IEEE80211_HW_SUPPORTS_PS;
        hw->wiphy->interface_modes =
                BIT(NL80211_IFTYPE_STATION) |
                BIT(NL80211_IFTYPE_ADHOC);
@@ -1361,7 +1419,6 @@ EXPORT_SYMBOL(iwl_setup_mac);
 
 int iwl_set_hw_params(struct iwl_priv *priv)
 {
-       priv->hw_params.sw_crypto = priv->cfg->mod_params->sw_crypto;
        priv->hw_params.max_rxq_size = RX_QUEUE_SIZE;
        priv->hw_params.max_rxq_log = RX_QUEUE_SIZE_LOG;
        if (priv->cfg->mod_params->amsdu_size_8K)
@@ -1370,6 +1427,8 @@ int iwl_set_hw_params(struct iwl_priv *priv)
                priv->hw_params.rx_buf_size = IWL_RX_BUF_SIZE_4K;
        priv->hw_params.max_pkt_size = priv->hw_params.rx_buf_size - 256;
 
+       priv->hw_params.max_beacon_itrvl = IWL_MAX_UCODE_BEACON_INTERVAL;
+
        if (priv->cfg->mod_params->disable_11n)
                priv->cfg->sku &= ~IWL_SKU_N;
 
index dabf663..a658410 100644 (file)
@@ -384,7 +384,6 @@ static inline __le32 iwl_hw_set_rate_n_flags(u8 rate, u32 flags)
 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, struct ieee80211_mgmt *frame,
                       const u8 *ie, int ie_len, int left);
@@ -398,7 +397,6 @@ void iwl_bg_scan_check(struct work_struct *data);
 void iwl_bg_abort_scan(struct work_struct *work);
 void iwl_bg_scan_completed(struct work_struct *work);
 void iwl_setup_scan_deferred_work(struct iwl_priv *priv);
-int iwl_send_scan_abort(struct iwl_priv *priv);
 
 /* For faster active scanning, scan will move to the next channel if fewer than
  * PLCP_QUIET_THRESH packets are heard on this channel within
@@ -556,6 +554,7 @@ extern void iwl_rx_reply_rx_phy(struct iwl_priv *priv,
 void iwl_rx_reply_compressed_ba(struct iwl_priv *priv,
                                           struct iwl_rx_mem_buffer *rxb);
 
+void iwl_setup_rxon_timing(struct iwl_priv *priv);
 static inline int iwl_send_rxon_assoc(struct iwl_priv *priv)
 {
        return priv->cfg->ops->hcmd->rxon_assoc(priv);
index 2cf014f..65bbce0 100644 (file)
@@ -36,6 +36,12 @@ struct iwl_priv;
 #define IWL_INFO(p, f, a...) dev_info(&((p)->pci_dev->dev), f, ## a)
 #define IWL_CRIT(p, f, a...) dev_crit(&((p)->pci_dev->dev), f, ## a)
 
+#define iwl_print_hex_error(priv, p, len)                              \
+do {                                                                   \
+       print_hex_dump(KERN_ERR, "iwl data: ",                          \
+                      DUMP_PREFIX_OFFSET, 16, 1, p, len, 1);           \
+} while (0)
+
 #ifdef CONFIG_IWLWIFI_DEBUG
 #define IWL_DEBUG(__priv, level, fmt, args...)                         \
 do {                                                                   \
index 11e08c0..f32ac74 100644 (file)
@@ -615,7 +615,10 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name)
        DEBUGFS_ADD_BOOL(disable_sensitivity, rf, &priv->disable_sens_cal);
        DEBUGFS_ADD_BOOL(disable_chain_noise, rf,
                         &priv->disable_chain_noise_cal);
-       DEBUGFS_ADD_BOOL(disable_tx_power, rf, &priv->disable_tx_power_cal);
+       if (((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_4965) ||
+           ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_3945))
+               DEBUGFS_ADD_BOOL(disable_tx_power, rf,
+                               &priv->disable_tx_power_cal);
        return 0;
 
 err:
@@ -646,7 +649,9 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv)
        DEBUGFS_REMOVE(priv->dbgfs->dir_data);
        DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_sensitivity);
        DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_chain_noise);
-       DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_tx_power);
+       if (((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_4965) ||
+           ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_3945))
+               DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_tx_power);
        DEBUGFS_REMOVE(priv->dbgfs->dir_rf);
        DEBUGFS_REMOVE(priv->dbgfs->dir_drv);
        kfree(priv->dbgfs);
index e2d620f..1a2fe37 100644 (file)
@@ -608,7 +608,7 @@ struct iwl_hw_params {
        u8  max_stations;
        u8  bcast_sta_id;
        u8 fat_channel;
-       u8 sw_crypto;
+       u8  max_beacon_itrvl;   /* in 1024 ms */
        u32 max_inst_size;
        u32 max_data_size;
        u32 max_bsm_size;
index 2b8d40b..66fe365 100644 (file)
@@ -927,12 +927,13 @@ static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv,
        hdr = (struct ieee80211_hdr *)rxb->skb->data;
 
        /*  in case of HW accelerated crypto and bad decryption, drop */
-       if (!priv->hw_params.sw_crypto &&
+       if (!priv->cfg->mod_params->sw_crypto &&
            iwl_set_decrypted_flag(priv, hdr, ampdu_status, stats))
                return;
 
        iwl_update_rx_stats(priv, le16_to_cpu(hdr->frame_control), len);
-       ieee80211_rx_irqsafe(priv->hw, rxb->skb, stats);
+       memcpy(IEEE80211_SKB_RXCB(rxb->skb), stats, sizeof(*stats));
+       ieee80211_rx_irqsafe(priv->hw, rxb->skb);
        priv->alloc_rxb_skb--;
        rxb->skb = NULL;
 }
index e26875d..00398d9 100644 (file)
@@ -109,7 +109,7 @@ int iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms)
 }
 EXPORT_SYMBOL(iwl_scan_cancel_timeout);
 
-int iwl_send_scan_abort(struct iwl_priv *priv)
+static int iwl_send_scan_abort(struct iwl_priv *priv)
 {
        int ret = 0;
        struct iwl_rx_packet *res;
@@ -150,7 +150,6 @@ int iwl_send_scan_abort(struct iwl_priv *priv)
 
        return ret;
 }
-EXPORT_SYMBOL(iwl_send_scan_abort);
 
 /* Service response to REPLY_SCAN_CMD (0x80) */
 static void iwl_rx_reply_scan(struct iwl_priv *priv,
@@ -322,7 +321,7 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv,
                                     u8 is_active, u8 n_probes,
                                     struct iwl_scan_channel *scan_ch)
 {
-       const struct ieee80211_channel *channels = NULL;
+       struct ieee80211_channel *chan;
        const struct ieee80211_supported_band *sband;
        const struct iwl_channel_info *ch_info;
        u16 passive_dwell = 0;
@@ -334,20 +333,19 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv,
        if (!sband)
                return 0;
 
-       channels = sband->channels;
-
        active_dwell = iwl_get_active_dwell_time(priv, band, n_probes);
        passive_dwell = iwl_get_passive_dwell_time(priv, band);
 
        if (passive_dwell <= active_dwell)
                passive_dwell = active_dwell + 1;
 
-       for (i = 0, added = 0; i < sband->n_channels; i++) {
-               if (channels[i].flags & IEEE80211_CHAN_DISABLED)
+       for (i = 0, added = 0; i < priv->scan_request->n_channels; i++) {
+               chan = priv->scan_request->channels[i];
+
+               if (chan->band != band)
                        continue;
 
-               channel =
-                       ieee80211_frequency_to_channel(channels[i].center_freq);
+               channel = ieee80211_frequency_to_channel(chan->center_freq);
                scan_ch->channel = cpu_to_le16(channel);
 
                ch_info = iwl_get_channel_info(priv, band, channel);
@@ -358,7 +356,7 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv,
                }
 
                if (!is_active || is_channel_passive(ch_info) ||
-                   (channels[i].flags & IEEE80211_CHAN_PASSIVE_SCAN))
+                   (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN))
                        scan_ch->type = SCAN_CHANNEL_TYPE_PASSIVE;
                else
                        scan_ch->type = SCAN_CHANNEL_TYPE_ACTIVE;
@@ -405,7 +403,7 @@ void iwl_init_scan_params(struct iwl_priv *priv)
                priv->scan_tx_ant[IEEE80211_BAND_2GHZ] = ant_idx;
 }
 
-int iwl_scan_initiate(struct iwl_priv *priv)
+static int iwl_scan_initiate(struct iwl_priv *priv)
 {
        if (!iwl_is_ready_rf(priv)) {
                IWL_DEBUG_SCAN(priv, "Aborting scan due to not ready.\n");
@@ -423,10 +421,6 @@ int iwl_scan_initiate(struct iwl_priv *priv)
        }
 
        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;
@@ -435,7 +429,6 @@ int iwl_scan_initiate(struct iwl_priv *priv)
 
        return 0;
 }
-EXPORT_SYMBOL(iwl_scan_initiate);
 
 #define IWL_DELAY_NEXT_SCAN (HZ*2)
 
@@ -444,7 +437,7 @@ int iwl_mac_hw_scan(struct ieee80211_hw *hw,
 {
        unsigned long flags;
        struct iwl_priv *priv = hw->priv;
-       int ret;
+       int ret, i;
 
        IWL_DEBUG_MAC80211(priv, "enter\n");
 
@@ -478,6 +471,10 @@ int iwl_mac_hw_scan(struct ieee80211_hw *hw,
                goto out_unlock;
        }
 
+       priv->scan_bands = 0;
+       for (i = 0; i < req->n_channels; i++)
+               priv->scan_bands |= BIT(req->channels[i]->band);
+
        priv->scan_request = req;
 
        ret = iwl_scan_initiate(priv);
index 9bbeec9..7073069 100644 (file)
@@ -348,6 +348,10 @@ int iwl_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq,
 
        txq->need_update = 0;
 
+       /* aggregation TX queues will get their ID when aggregation begins */
+       if (txq_id <= IWL_TX_FIFO_AC3)
+               txq->swq_id = txq_id;
+
        /* TFD_QUEUE_SIZE_MAX must be power-of-two size, otherwise
         * iwl_queue_inc_wrap and iwl_queue_dec_wrap are broken. */
        BUILD_BUG_ON(TFD_QUEUE_SIZE_MAX & (TFD_QUEUE_SIZE_MAX - 1));
@@ -734,8 +738,7 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
 
        IWL_DEBUG_TX(priv, "station Id %d\n", sta_id);
 
-       swq_id = skb_get_queue_mapping(skb);
-       txq_id = swq_id;
+       txq_id = skb_get_queue_mapping(skb);
        if (ieee80211_is_data_qos(fc)) {
                qc = ieee80211_get_qos_ctl(hdr);
                tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK;
@@ -746,16 +749,14 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
                hdr->seq_ctrl |= cpu_to_le16(seq_number);
                seq_number += 0x10;
                /* aggregation is on for this <sta,tid> */
-               if (info->flags & IEEE80211_TX_CTL_AMPDU) {
+               if (info->flags & IEEE80211_TX_CTL_AMPDU)
                        txq_id = priv->stations[sta_id].tid[tid].agg.txq_id;
-                       swq_id = iwl_virtual_agg_queue_num(swq_id, txq_id);
-               }
                priv->stations[sta_id].tid[tid].tfds_in_queue++;
        }
 
        txq = &priv->txq[txq_id];
+       swq_id = txq->swq_id;
        q = &txq->q;
-       txq->swq_id = swq_id;
 
        spin_lock_irqsave(&priv->lock, flags);
 
@@ -1109,7 +1110,7 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
                  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);
+               iwl_print_hex_error(priv, rxb, 32);
                return;
        }
 
@@ -1187,6 +1188,7 @@ int iwl_tx_agg_start(struct iwl_priv *priv, const u8 *ra, u16 tid, u16 *ssn)
        tid_data = &priv->stations[sta_id].tid[tid];
        *ssn = SEQ_TO_SN(tid_data->seq_number);
        tid_data->agg.txq_id = txq_id;
+       priv->txq[txq_id].swq_id = iwl_virtual_agg_queue_num(tx_fifo, txq_id);
        spin_unlock_irqrestore(&priv->sta_lock, flags);
 
        ret = priv->cfg->ops->lib->txq_agg_enable(priv, txq_id, tx_fifo,
index 956798f..7ff95f8 100644 (file)
@@ -361,76 +361,6 @@ static void iwl3945_unset_hw_params(struct iwl_priv *priv)
                                    priv->shared_phys);
 }
 
-#define MAX_UCODE_BEACON_INTERVAL      1024
-#define INTEL_CONN_LISTEN_INTERVAL     cpu_to_le16(0xA)
-
-static __le16 iwl3945_adjust_beacon_interval(u16 beacon_val)
-{
-       u16 new_val = 0;
-       u16 beacon_factor = 0;
-
-       beacon_factor =
-           (beacon_val + MAX_UCODE_BEACON_INTERVAL)
-               / MAX_UCODE_BEACON_INTERVAL;
-       new_val = beacon_val / beacon_factor;
-
-       return cpu_to_le16(new_val);
-}
-
-static void iwl3945_setup_rxon_timing(struct iwl_priv *priv)
-{
-       u64 interval_tm_unit;
-       u64 tsf, result;
-       unsigned long flags;
-       struct ieee80211_conf *conf = NULL;
-       u16 beacon_int = 0;
-
-       conf = ieee80211_get_hw_conf(priv->hw);
-
-       spin_lock_irqsave(&priv->lock, flags);
-       priv->rxon_timing.timestamp = cpu_to_le64(priv->timestamp);
-       priv->rxon_timing.listen_interval = INTEL_CONN_LISTEN_INTERVAL;
-
-       tsf = priv->timestamp;
-
-       beacon_int = priv->beacon_int;
-       spin_unlock_irqrestore(&priv->lock, flags);
-
-       if (priv->iw_mode == NL80211_IFTYPE_STATION) {
-               if (beacon_int == 0) {
-                       priv->rxon_timing.beacon_interval = cpu_to_le16(100);
-                       priv->rxon_timing.beacon_init_val = cpu_to_le32(102400);
-               } else {
-                       priv->rxon_timing.beacon_interval =
-                               cpu_to_le16(beacon_int);
-                       priv->rxon_timing.beacon_interval =
-                           iwl3945_adjust_beacon_interval(
-                               le16_to_cpu(priv->rxon_timing.beacon_interval));
-               }
-
-               priv->rxon_timing.atim_window = 0;
-       } else {
-               priv->rxon_timing.beacon_interval =
-                       iwl3945_adjust_beacon_interval(
-                               priv->vif->bss_conf.beacon_int);
-               /* TODO: we need to get atim_window from upper stack
-                * for now we set to 0 */
-               priv->rxon_timing.atim_window = 0;
-       }
-
-       interval_tm_unit =
-               (le16_to_cpu(priv->rxon_timing.beacon_interval) * 1024);
-       result = do_div(tsf, interval_tm_unit);
-       priv->rxon_timing.beacon_init_val =
-           cpu_to_le32((u32) ((u64) interval_tm_unit - result));
-
-       IWL_DEBUG_ASSOC(priv,
-               "beacon interval %d beacon timer %d beacon tim %d\n",
-               le16_to_cpu(priv->rxon_timing.beacon_interval),
-               le32_to_cpu(priv->rxon_timing.beacon_init_val),
-               le16_to_cpu(priv->rxon_timing.atim_window));
-}
-
 static void iwl3945_build_tx_cmd_hwcrypto(struct iwl_priv *priv,
                                      struct ieee80211_tx_info *info,
                                      struct iwl_cmd *cmd,
@@ -1844,7 +1774,7 @@ static int iwl3945_get_channels_for_scan(struct iwl_priv *priv,
                                     u8 is_active, u8 n_probes,
                                     struct iwl3945_scan_channel *scan_ch)
 {
-       const struct ieee80211_channel *channels = NULL;
+       struct ieee80211_channel *chan;
        const struct ieee80211_supported_band *sband;
        const struct iwl_channel_info *ch_info;
        u16 passive_dwell = 0;
@@ -1855,19 +1785,19 @@ static int iwl3945_get_channels_for_scan(struct iwl_priv *priv,
        if (!sband)
                return 0;
 
-       channels = sband->channels;
-
        active_dwell = iwl_get_active_dwell_time(priv, band, n_probes);
        passive_dwell = iwl_get_passive_dwell_time(priv, band);
 
        if (passive_dwell <= active_dwell)
                passive_dwell = active_dwell + 1;
 
-       for (i = 0, added = 0; i < sband->n_channels; i++) {
-               if (channels[i].flags & IEEE80211_CHAN_DISABLED)
+       for (i = 0, added = 0; i < priv->scan_request->n_channels; i++) {
+               chan = priv->scan_request->channels[i];
+
+               if (chan->band != band)
                        continue;
 
-               scan_ch->channel = channels[i].hw_value;
+               scan_ch->channel = chan->hw_value;
 
                ch_info = iwl_get_channel_info(priv, band, scan_ch->channel);
                if (!is_channel_valid(ch_info)) {
@@ -1882,7 +1812,7 @@ static int iwl3945_get_channels_for_scan(struct iwl_priv *priv,
                 *  and use long active_dwell time.
                 */
                if (!is_active || is_channel_passive(ch_info) ||
-                   (channels[i].flags & IEEE80211_CHAN_PASSIVE_SCAN)) {
+                   (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN)) {
                        scan_ch->type = 0;      /* passive */
                        if (IWL_UCODE_API(priv->ucode_ver) == 1)
                                scan_ch->active_dwell = cpu_to_le16(passive_dwell - 1);
@@ -3066,7 +2996,7 @@ void iwl3945_post_associate(struct iwl_priv *priv)
        iwlcore_commit_rxon(priv);
 
        memset(&priv->rxon_timing, 0, sizeof(struct iwl_rxon_time_cmd));
-       iwl3945_setup_rxon_timing(priv);
+       iwl_setup_rxon_timing(priv);
        rc = iwl_send_cmd_pdu(priv, REPLY_RXON_TIMING,
                              sizeof(priv->rxon_timing), &priv->rxon_timing);
        if (rc)
@@ -3261,7 +3191,7 @@ void iwl3945_config_ap(struct iwl_priv *priv)
 
                /* RXON Timing */
                memset(&priv->rxon_timing, 0, sizeof(struct iwl_rxon_time_cmd));
-               iwl3945_setup_rxon_timing(priv);
+               iwl_setup_rxon_timing(priv);
                rc = iwl_send_cmd_pdu(priv, REPLY_RXON_TIMING,
                                      sizeof(priv->rxon_timing),
                                      &priv->rxon_timing);
index 96f714e..54bebba 100644 (file)
@@ -23,6 +23,7 @@
 
 #include <linux/kernel.h>
 #include <linux/netdevice.h>
+#include <linux/etherdevice.h>
 #include <linux/wireless.h>
 #include <linux/ieee80211.h>
 #include <net/cfg80211.h>
@@ -130,6 +131,181 @@ static struct ieee80211_supported_band iwm_band_5ghz = {
        .n_bitrates = iwm_a_rates_size,
 };
 
+static int iwm_key_init(struct iwm_key *key, u8 key_index,
+                       const u8 *mac_addr, struct key_params *params)
+{
+       key->hdr.key_idx = key_index;
+       if (!mac_addr || is_broadcast_ether_addr(mac_addr)) {
+               key->hdr.multicast = 1;
+               memset(key->hdr.mac, 0xff, ETH_ALEN);
+       } else {
+               key->hdr.multicast = 0;
+               memcpy(key->hdr.mac, mac_addr, ETH_ALEN);
+       }
+
+       if (params) {
+               if (params->key_len > WLAN_MAX_KEY_LEN ||
+                   params->seq_len > IW_ENCODE_SEQ_MAX_SIZE)
+                       return -EINVAL;
+
+               key->cipher = params->cipher;
+               key->key_len = params->key_len;
+               key->seq_len = params->seq_len;
+               memcpy(key->key, params->key, key->key_len);
+               memcpy(key->seq, params->seq, key->seq_len);
+       }
+
+       return 0;
+}
+
+static int iwm_reset_profile(struct iwm_priv *iwm)
+{
+       int ret;
+
+       if (!iwm->umac_profile_active)
+               return 0;
+
+       /*
+        * If there is a current active profile, but no
+        * default key, it's not worth trying to associate again.
+        */
+       if (iwm->default_key < 0)
+               return 0;
+
+       /*
+        * Here we have an active profile, but a key setting changed.
+        * We thus have to invalidate the current profile, and push the
+        * new one. Keys will be pushed when association takes place.
+        */
+       ret = iwm_invalidate_mlme_profile(iwm);
+       if (ret < 0) {
+               IWM_ERR(iwm, "Couldn't invalidate profile\n");
+               return ret;
+       }
+
+       return iwm_send_mlme_profile(iwm);
+}
+
+static int iwm_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
+                               u8 key_index, const u8 *mac_addr,
+                               struct key_params *params)
+{
+       struct iwm_priv *iwm = ndev_to_iwm(ndev);
+       struct iwm_key *key = &iwm->keys[key_index];
+       int ret;
+
+       IWM_DBG_WEXT(iwm, DBG, "Adding key for %pM\n", mac_addr);
+
+       memset(key, 0, sizeof(struct iwm_key));
+       ret = iwm_key_init(key, key_index, mac_addr, params);
+       if (ret < 0) {
+               IWM_ERR(iwm, "Invalid key_params\n");
+               return ret;
+       }
+
+       /*
+        * The WEP keys can be set before or after setting the essid.
+        * We need to handle both cases by simply pushing the keys after
+        * we send the profile.
+        * If the profile is not set yet (i.e. we're pushing keys before
+        * the essid), we set the cipher appropriately.
+        * If the profile is set, we havent associated yet because our
+        * cipher was incorrectly set. So we invalidate and send the
+        * profile again.
+        */
+       if (key->cipher == WLAN_CIPHER_SUITE_WEP40 ||
+           key->cipher == WLAN_CIPHER_SUITE_WEP104) {
+               u8 *ucast_cipher = &iwm->umac_profile->sec.ucast_cipher;
+               u8 *mcast_cipher = &iwm->umac_profile->sec.mcast_cipher;
+
+               IWM_DBG_WEXT(iwm, DBG, "WEP key\n");
+
+               if (key->cipher == WLAN_CIPHER_SUITE_WEP40)
+                       *ucast_cipher = *mcast_cipher = UMAC_CIPHER_TYPE_WEP_40;
+               if (key->cipher == WLAN_CIPHER_SUITE_WEP104)
+                       *ucast_cipher = *mcast_cipher =
+                               UMAC_CIPHER_TYPE_WEP_104;
+
+               return iwm_reset_profile(iwm);
+       }
+
+       return iwm_set_key(iwm, 0, key);
+}
+
+static int iwm_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev,
+                               u8 key_index, const u8 *mac_addr, void *cookie,
+                               void (*callback)(void *cookie,
+                                                struct key_params*))
+{
+       struct iwm_priv *iwm = ndev_to_iwm(ndev);
+       struct iwm_key *key = &iwm->keys[key_index];
+       struct key_params params;
+
+       IWM_DBG_WEXT(iwm, DBG, "Getting key %d\n", key_index);
+
+       memset(&params, 0, sizeof(params));
+
+       params.cipher = key->cipher;
+       params.key_len = key->key_len;
+       params.seq_len = key->seq_len;
+       params.seq = key->seq;
+       params.key = key->key;
+
+       callback(cookie, &params);
+
+       return key->key_len ? 0 : -ENOENT;
+}
+
+
+static int iwm_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
+                               u8 key_index, const u8 *mac_addr)
+{
+       struct iwm_priv *iwm = ndev_to_iwm(ndev);
+       struct iwm_key *key = &iwm->keys[key_index];
+
+       if (!iwm->keys[key_index].key_len) {
+               IWM_DBG_WEXT(iwm, DBG, "Key %d not used\n", key_index);
+               return 0;
+       }
+
+       if (key_index == iwm->default_key)
+               iwm->default_key = -1;
+
+       /* If the interface is down, we just cache this */
+       if (!test_bit(IWM_STATUS_READY, &iwm->status))
+               return 0;
+
+       return iwm_set_key(iwm, 1, key);
+}
+
+static int iwm_cfg80211_set_default_key(struct wiphy *wiphy,
+                                       struct net_device *ndev,
+                                       u8 key_index)
+{
+       struct iwm_priv *iwm = ndev_to_iwm(ndev);
+       int ret;
+
+       IWM_DBG_WEXT(iwm, DBG, "Default key index is: %d\n", key_index);
+
+       if (!iwm->keys[key_index].key_len) {
+               IWM_ERR(iwm, "Key %d not used\n", key_index);
+               return -EINVAL;
+       }
+
+       iwm->default_key = key_index;
+
+       /* If the interface is down, we just cache this */
+       if (!test_bit(IWM_STATUS_READY, &iwm->status))
+               return 0;
+
+       ret = iwm_set_tx_key(iwm, key_index);
+       if (ret < 0)
+               return ret;
+
+       return iwm_reset_profile(iwm);
+}
+
+
 int iwm_cfg80211_inform_bss(struct iwm_priv *iwm)
 {
        struct wiphy *wiphy = iwm_to_wiphy(iwm);
@@ -167,20 +343,15 @@ int iwm_cfg80211_inform_bss(struct iwm_priv *iwm)
        return 0;
 }
 
-static int iwm_cfg80211_change_iface(struct wiphy *wiphy, int ifindex,
+static int iwm_cfg80211_change_iface(struct wiphy *wiphy,
+                                    struct net_device *ndev,
                                     enum nl80211_iftype type, u32 *flags,
                                     struct vif_params *params)
 {
-       struct net_device *ndev;
        struct wireless_dev *wdev;
        struct iwm_priv *iwm;
        u32 old_mode;
 
-       /* we're under RTNL */
-       ndev = __dev_get_by_index(&init_net, ifindex);
-       if (!ndev)
-               return -ENODEV;
-
        wdev = ndev->ieee80211_ptr;
        iwm = ndev_to_iwm(ndev);
        old_mode = iwm->conf.mode;
@@ -329,12 +500,62 @@ static int iwm_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
        return 0;
 }
 
+static int iwm_cfg80211_set_txpower(struct wiphy *wiphy,
+                                   enum tx_power_setting type, int dbm)
+{
+       switch (type) {
+       case TX_POWER_AUTOMATIC:
+               return 0;
+       default:
+               return -EOPNOTSUPP;
+       }
+
+       return 0;
+}
+
+static int iwm_cfg80211_get_txpower(struct wiphy *wiphy, int *dbm)
+{
+       struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
+
+       *dbm = iwm->txpower;
+
+       return 0;
+}
+
+static int iwm_cfg80211_set_power_mgmt(struct wiphy *wiphy,
+                                      struct net_device *dev,
+                                      bool enabled, int timeout)
+{
+       struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
+       u32 power_index;
+
+       if (enabled)
+               power_index = IWM_POWER_INDEX_DEFAULT;
+       else
+               power_index = IWM_POWER_INDEX_MIN;
+
+       if (power_index == iwm->conf.power_index)
+               return 0;
+
+       iwm->conf.power_index = power_index;
+
+       return iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX,
+                                      CFG_POWER_INDEX, iwm->conf.power_index);
+}
+
 static struct cfg80211_ops iwm_cfg80211_ops = {
        .change_virtual_intf = iwm_cfg80211_change_iface,
+       .add_key = iwm_cfg80211_add_key,
+       .get_key = iwm_cfg80211_get_key,
+       .del_key = iwm_cfg80211_del_key,
+       .set_default_key = iwm_cfg80211_set_default_key,
        .scan = iwm_cfg80211_scan,
        .set_wiphy_params = iwm_cfg80211_set_wiphy_params,
        .join_ibss = iwm_cfg80211_join_ibss,
        .leave_ibss = iwm_cfg80211_leave_ibss,
+       .set_tx_power = iwm_cfg80211_set_txpower,
+       .get_tx_power = iwm_cfg80211_get_txpower,
+       .set_power_mgmt = iwm_cfg80211_set_power_mgmt,
 };
 
 struct wireless_dev *iwm_wdev_alloc(int sizeof_bus, struct device *dev)
index 834a7f5..0d35afe 100644 (file)
@@ -70,14 +70,28 @@ static int iwm_send_lmac_ptrough_cmd(struct iwm_priv *iwm,
 int iwm_send_wifi_if_cmd(struct iwm_priv *iwm, void *payload, u16 payload_size,
                         bool resp)
 {
+       struct iwm_umac_wifi_if *hdr = (struct iwm_umac_wifi_if *)payload;
        struct iwm_udma_wifi_cmd udma_cmd = UDMA_UMAC_INIT;
        struct iwm_umac_cmd umac_cmd;
+       int ret;
+       u8 oid = hdr->oid;
 
        umac_cmd.id = UMAC_CMD_OPCODE_WIFI_IF_WRAPPER;
        umac_cmd.resp = resp;
 
-       return iwm_hal_send_umac_cmd(iwm, &udma_cmd, &umac_cmd,
-                                    payload, payload_size);
+       ret = iwm_hal_send_umac_cmd(iwm, &udma_cmd, &umac_cmd,
+                                   payload, payload_size);
+
+       if (resp) {
+               ret = wait_event_interruptible_timeout(iwm->wifi_ntfy_queue,
+                                  test_and_clear_bit(oid, &iwm->wifi_ntfy[0]),
+                                  3 * HZ);
+
+               if (!ret)
+                       ret = -EBUSY;
+       }
+
+       return ret;
 }
 
 static struct coex_event iwm_sta_xor_prio_tbl[COEX_EVENTS_NUM] =
@@ -106,7 +120,7 @@ static struct coex_event iwm_sta_cm_prio_tbl[COEX_EVENTS_NUM] =
        {4, 3, 0, COEX_UNASSOC_MANUAL_SCAN_FLAGS},
        {3, 3, 0, COEX_UNASSOC_AUTO_SCAN_FLAGS},
        {5, 5, 0, COEX_CALIBRATION_FLAGS},
-       {4, 4, 0, COEX_PERIODIC_CALIBRATION_FLAGS},
+       {3, 3, 0, COEX_PERIODIC_CALIBRATION_FLAGS},
        {5, 4, 0, COEX_CONNECTION_ESTAB_FLAGS},
        {4, 4, 0, COEX_ASSOCIATED_IDLE_FLAGS},
        {4, 4, 0, COEX_ASSOC_MANUAL_SCAN_FLAGS},
@@ -331,8 +345,7 @@ int iwm_umac_set_config_var(struct iwm_priv *iwm, u16 key,
        return ret;
 }
 
-int iwm_send_umac_config(struct iwm_priv *iwm,
-                        __le32 reset_flags)
+int iwm_send_umac_config(struct iwm_priv *iwm, __le32 reset_flags)
 {
        int ret;
 
@@ -360,6 +373,12 @@ int iwm_send_umac_config(struct iwm_priv *iwm,
                return ret;
 
        ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX,
+                                     CFG_WIRELESS_MODE,
+                                     iwm->conf.wireless_mode);
+       if (ret < 0)
+               return ret;
+
+       ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX,
                                      CFG_COEX_MODE, iwm->conf.coexist_mode);
        if (ret < 0)
                return ret;
@@ -401,7 +420,7 @@ int iwm_send_umac_config(struct iwm_priv *iwm,
                return ret;
 
        ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX,
-                                     CFG_PM_CTRL_FLAGS, 0x30001);
+                                     CFG_PM_CTRL_FLAGS, 0x1);
        if (ret < 0)
                return ret;
 
@@ -510,9 +529,6 @@ int iwm_set_tx_key(struct iwm_priv *iwm, u8 key_idx)
 {
        struct iwm_umac_tx_key_id tx_key_id;
 
-       if (!iwm->default_key || !iwm->default_key->in_use)
-               return -EINVAL;
-
        tx_key_id.hdr.oid = UMAC_WIFI_IF_CMD_GLOBAL_TX_KEY_ID;
        tx_key_id.hdr.buf_size = cpu_to_le16(sizeof(struct iwm_umac_tx_key_id) -
                                             sizeof(struct iwm_umac_wifi_if));
@@ -555,10 +571,9 @@ static int iwm_check_profile(struct iwm_priv *iwm)
        return 0;
 }
 
-int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key,
-               struct iwm_key *key)
+int iwm_set_key(struct iwm_priv *iwm, bool remove, struct iwm_key *key)
 {
-       int ret;
+       int ret = 0;
        u8 cmd[64], *sta_addr, *key_data, key_len;
        s8 key_idx;
        u16 cmd_size = 0;
@@ -568,9 +583,6 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key,
        struct iwm_umac_key_tkip *tkip = (struct iwm_umac_key_tkip *)cmd;
        struct iwm_umac_key_ccmp *ccmp = (struct iwm_umac_key_ccmp *)cmd;
 
-       if (set_tx_key)
-               iwm->default_key = key;
-
        /*
         * We check if our current profile is valid.
         * If not, we dont push the key, we just cache them,
@@ -589,8 +601,7 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key,
        key_idx = key->hdr.key_idx;
 
        if (!remove) {
-               IWM_DBG_WEXT(iwm, DBG, "key_idx:%d set tx key:%d\n",
-                            key_idx, set_tx_key);
+               IWM_DBG_WEXT(iwm, DBG, "key_idx:%d\n", key_idx);
                IWM_DBG_WEXT(iwm, DBG, "key_len:%d\n", key_len);
                IWM_DBG_WEXT(iwm, DBG, "MAC:%pM, idx:%d, multicast:%d\n",
                       key_hdr->mac, key_hdr->key_idx, key_hdr->multicast);
@@ -602,8 +613,8 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key,
                             iwm->umac_profile->sec.auth_type,
                             iwm->umac_profile->sec.flags);
 
-               switch (key->alg) {
-               case UMAC_CIPHER_TYPE_WEP_40:
+               switch (key->cipher) {
+               case WLAN_CIPHER_SUITE_WEP40:
                        wep40->hdr.oid = UMAC_WIFI_IF_CMD_ADD_WEP40_KEY;
                        wep40->hdr.buf_size =
                                cpu_to_le16(sizeof(struct iwm_umac_key_wep40) -
@@ -617,7 +628,7 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key,
                        cmd_size = sizeof(struct iwm_umac_key_wep40);
                        break;
 
-               case UMAC_CIPHER_TYPE_WEP_104:
+               case WLAN_CIPHER_SUITE_WEP104:
                        wep104->hdr.oid = UMAC_WIFI_IF_CMD_ADD_WEP104_KEY;
                        wep104->hdr.buf_size =
                                cpu_to_le16(sizeof(struct iwm_umac_key_wep104) -
@@ -631,7 +642,7 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key,
                        cmd_size = sizeof(struct iwm_umac_key_wep104);
                        break;
 
-               case UMAC_CIPHER_TYPE_CCMP:
+               case WLAN_CIPHER_SUITE_CCMP:
                        key_hdr->key_idx++;
                        ccmp->hdr.oid = UMAC_WIFI_IF_CMD_ADD_CCMP_KEY;
                        ccmp->hdr.buf_size =
@@ -643,13 +654,13 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key,
 
                        memcpy(ccmp->key, key_data, key_len);
 
-                       if (key->flags & IW_ENCODE_EXT_RX_SEQ_VALID)
-                               memcpy(ccmp->iv_count, key->rx_seq, 6);
+                       if (key->seq_len)
+                               memcpy(ccmp->iv_count, key->seq, key->seq_len);
 
                        cmd_size = sizeof(struct iwm_umac_key_ccmp);
                        break;
 
-               case UMAC_CIPHER_TYPE_TKIP:
+               case WLAN_CIPHER_SUITE_TKIP:
                        key_hdr->key_idx++;
                        tkip->hdr.oid = UMAC_WIFI_IF_CMD_ADD_TKIP_KEY;
                        tkip->hdr.buf_size =
@@ -666,8 +677,8 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key,
                               key_data + IWM_TKIP_KEY_SIZE + IWM_TKIP_MIC_SIZE,
                               IWM_TKIP_MIC_SIZE);
 
-                       if (key->flags & IW_ENCODE_EXT_RX_SEQ_VALID)
-                               memcpy(ccmp->iv_count, key->rx_seq, 6);
+                       if (key->seq_len)
+                               memcpy(ccmp->iv_count, key->seq, key->seq_len);
 
                        cmd_size = sizeof(struct iwm_umac_key_tkip);
                        break;
@@ -676,8 +687,8 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key,
                        return -ENOTSUPP;
                }
 
-               if ((key->alg == UMAC_CIPHER_TYPE_CCMP) ||
-                   (key->alg == UMAC_CIPHER_TYPE_TKIP))
+               if ((key->cipher == WLAN_CIPHER_SUITE_TKIP) ||
+                   (key->cipher == WLAN_CIPHER_SUITE_CCMP))
                        /*
                         * UGLY_UGLY_UGLY
                         * Copied HACK from the MWG driver.
@@ -688,23 +699,11 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key,
                        schedule_timeout_interruptible(usecs_to_jiffies(300));
 
                ret =  iwm_send_wifi_if_cmd(iwm, cmd, cmd_size, 1);
-               if (ret < 0)
-                       goto err;
-
-               /*
-                * We need a default key only if it is set and
-                * if we're doing WEP.
-                */
-               if (iwm->default_key == key &&
-                       ((key->alg == UMAC_CIPHER_TYPE_WEP_40) ||
-                        (key->alg == UMAC_CIPHER_TYPE_WEP_104))) {
-                       ret = iwm_set_tx_key(iwm, key_idx);
-                       if (ret < 0)
-                               goto err;
-               }
        } else {
                struct iwm_umac_key_remove key_remove;
 
+               IWM_DBG_WEXT(iwm, ERR, "Removing key_idx:%d\n", key_idx);
+
                key_remove.hdr.oid = UMAC_WIFI_IF_CMD_REMOVE_KEY;
                key_remove.hdr.buf_size =
                        cpu_to_le16(sizeof(struct iwm_umac_key_remove) -
@@ -718,13 +717,9 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key,
                if (ret < 0)
                        return ret;
 
-               iwm->keys[key_idx].in_use = 0;
+               iwm->keys[key_idx].key_len = 0;
        }
 
-       return 0;
-
- err:
-       kfree(key);
        return ret;
 }
 
@@ -746,31 +741,25 @@ int iwm_send_mlme_profile(struct iwm_priv *iwm)
                return ret;
        }
 
-       /* Wait for the profile to be active */
-       ret = wait_event_interruptible_timeout(iwm->mlme_queue,
-                                              iwm->umac_profile_active == 1,
-                                              3 * HZ);
-       if (!ret)
-               return -EBUSY;
-
-
        for (i = 0; i < IWM_NUM_KEYS; i++)
-               if (iwm->keys[i].in_use) {
-                       int default_key = 0;
+               if (iwm->keys[i].key_len) {
                        struct iwm_key *key = &iwm->keys[i];
 
-                       if (key == iwm->default_key)
-                               default_key = 1;
-
                        /* Wait for the profile before sending the keys */
                        wait_event_interruptible_timeout(iwm->mlme_queue,
                             (test_bit(IWM_STATUS_ASSOCIATING, &iwm->status) ||
                              test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)),
                                                         3 * HZ);
 
-                       ret = iwm_set_key(iwm, 0, default_key, key);
+                       ret = iwm_set_key(iwm, 0, key);
                        if (ret < 0)
                                return ret;
+
+                       if (iwm->default_key == i) {
+                               ret = iwm_set_tx_key(iwm, i);
+                               if (ret < 0)
+                                       return ret;
+                       }
                }
 
        return 0;
@@ -778,8 +767,8 @@ int iwm_send_mlme_profile(struct iwm_priv *iwm)
 
 int iwm_invalidate_mlme_profile(struct iwm_priv *iwm)
 {
-       int ret;
        struct iwm_umac_invalidate_profile invalid;
+       int ret;
 
        invalid.hdr.oid = UMAC_WIFI_IF_CMD_INVALIDATE_PROFILE;
        invalid.hdr.buf_size =
@@ -793,8 +782,7 @@ int iwm_invalidate_mlme_profile(struct iwm_priv *iwm)
                return ret;
 
        ret = wait_event_interruptible_timeout(iwm->mlme_queue,
-                                (iwm->umac_profile_active == 0),
-                                              2 * HZ);
+                               (iwm->umac_profile_active == 0), 2 * HZ);
        if (!ret)
                return -EBUSY;
 
index 36b13a1..e24d5b6 100644 (file)
@@ -106,8 +106,7 @@ enum {
        CFG_TLC_SPATIAL_STREAM_SUPPORTED,
        CFG_TLC_RETRY_PER_RATE,
        CFG_TLC_RETRY_PER_HT_RATE,
-       CFG_TLC_FIXED_RATE,
-       CFG_TLC_FIXED_RATE_FLAGS,
+       CFG_TLC_FIXED_MCS,
        CFG_TLC_CONTROL_FLAGS,
        CFG_TLC_SR_MIN_FAIL,
        CFG_TLC_SR_MIN_PASS,
@@ -232,6 +231,7 @@ struct iwm_umac_cmd_get_channel_list {
 /* Wireless mode */
 #define WIRELESS_MODE_11A  0x1
 #define WIRELESS_MODE_11G  0x2
+#define WIRELESS_MODE_11N  0x4
 
 #define UMAC_PROFILE_EX_IE_REQUIRED    0x1
 #define UMAC_PROFILE_QOS_ALLOWED       0x2
@@ -406,8 +406,7 @@ int iwm_send_mlme_profile(struct iwm_priv *iwm);
 int iwm_invalidate_mlme_profile(struct iwm_priv *iwm);
 int iwm_send_packet(struct iwm_priv *iwm, struct sk_buff *skb, int pool_id);
 int iwm_set_tx_key(struct iwm_priv *iwm, u8 key_idx);
-int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key,
-               struct iwm_key *key);
+int iwm_set_key(struct iwm_priv *iwm, bool remove, struct iwm_key *key);
 int iwm_send_umac_stats_req(struct iwm_priv *iwm, u32 flags);
 int iwm_send_umac_channel_list(struct iwm_priv *iwm);
 int iwm_scan_ssids(struct iwm_priv *iwm, struct cfg80211_ssid *ssids,
index 0f34b84..365910f 100644 (file)
@@ -156,10 +156,6 @@ int iwm_eeprom_init(struct iwm_priv *iwm)
                return -ENOMEM;
 
        for (i = IWM_EEPROM_FIRST; i < IWM_EEPROM_LAST; i++) {
-#ifdef CONFIG_IWM_B0_HW_SUPPORT
-               if (iwm->conf.hw_b0 && (i >= IWM_EEPROM_INDIRECT_OFFSET))
-                       break;
-#endif
                ret = iwm_eeprom_read(iwm, i);
                if (ret < 0) {
                        IWM_ERR(iwm, "Couldn't read eeprom entry #%d: %s\n",
index ec1a15a..0f32cab 100644 (file)
@@ -275,6 +275,7 @@ static int iwm_load_lmac(struct iwm_priv *iwm, const char *img_name)
  */
 int iwm_load_fw(struct iwm_priv *iwm)
 {
+       unsigned long init_calib_map, periodic_calib_map;
        int ret;
 
        /* We first start downloading the UMAC */
@@ -315,23 +316,19 @@ int iwm_load_fw(struct iwm_priv *iwm)
                return ret;
        }
 
-#ifdef CONFIG_IWM_B0_HW_SUPPORT
-       if (iwm->conf.hw_b0) {
-               clear_bit(PHY_CALIBRATE_RX_IQ_CMD, &iwm->conf.init_calib_map);
-               clear_bit(PHY_CALIBRATE_RX_IQ_CMD,
-                         &iwm->conf.periodic_calib_map);
-       }
-#endif
+       init_calib_map = iwm->conf.calib_map & IWM_CALIB_MAP_INIT_MSK;
+       periodic_calib_map = IWM_CALIB_MAP_PER_LMAC(iwm->conf.calib_map);
+
        /* Read RX IQ calibration result from EEPROM */
-       if (test_bit(PHY_CALIBRATE_RX_IQ_CMD, &iwm->conf.init_calib_map)) {
+       if (test_bit(PHY_CALIBRATE_RX_IQ_CMD, &init_calib_map)) {
                iwm_store_rxiq_calib_result(iwm);
                set_bit(PHY_CALIBRATE_RX_IQ_CMD, &iwm->calib_done_map);
        }
 
        iwm_send_prio_table(iwm);
-       iwm_send_init_calib_cfg(iwm, iwm->conf.init_calib_map);
+       iwm_send_init_calib_cfg(iwm, init_calib_map);
 
-       while (iwm->calib_done_map != iwm->conf.init_calib_map) {
+       while (iwm->calib_done_map != init_calib_map) {
                ret = iwm_notif_handle(iwm, CALIBRATION_RES_NOTIFICATION,
                                       IWM_SRC_LMAC, WAIT_NOTIF_TIMEOUT);
                if (ret) {
@@ -340,7 +337,7 @@ int iwm_load_fw(struct iwm_priv *iwm)
                }
                IWM_DBG_FW(iwm, DBG, "Got calibration result. calib_done_map: "
                           "0x%lx, requested calibrations: 0x%lx\n",
-                          iwm->calib_done_map, iwm->conf.init_calib_map);
+                          iwm->calib_done_map, init_calib_map);
        }
 
        /* Handle LMAC CALIBRATION_COMPLETE notification */
@@ -378,7 +375,7 @@ int iwm_load_fw(struct iwm_priv *iwm)
 
        iwm_send_prio_table(iwm);
        iwm_send_calib_results(iwm);
-       iwm_send_periodic_calib_cfg(iwm, iwm->conf.periodic_calib_map);
+       iwm_send_periodic_calib_cfg(iwm, periodic_calib_map);
 
        return 0;
 
index 77c339f..79d9d89 100644 (file)
@@ -52,8 +52,6 @@
 #define IWM_COPYRIGHT "Copyright(c) 2009 Intel Corporation"
 #define IWM_AUTHOR "<ilw@linux.intel.com>"
 
-#define CONFIG_IWM_B0_HW_SUPPORT       1
-
 #define IWM_SRC_LMAC   UMAC_HDI_IN_SOURCE_FHRX
 #define IWM_SRC_UDMA   UMAC_HDI_IN_SOURCE_UDMA
 #define IWM_SRC_UMAC   UMAC_HDI_IN_SOURCE_FW
@@ -65,8 +63,7 @@
 
 struct iwm_conf {
        u32 sdio_ior_timeout;
-       unsigned long init_calib_map;
-       unsigned long periodic_calib_map;
+       unsigned long calib_map;
        bool reset_on_fatal_err;
        bool auto_connect;
        bool wimax_not_present;
@@ -87,9 +84,6 @@ struct iwm_conf {
        u8 ibss_channel;
 
        u8 mac_addr[ETH_ALEN];
-#ifdef CONFIG_IWM_B0_HW_SUPPORT
-       bool hw_b0;
-#endif
 };
 
 enum {
@@ -162,13 +156,11 @@ struct iwm_umac_key_hdr {
 
 struct iwm_key {
        struct iwm_umac_key_hdr hdr;
-       u8 in_use;
-       u8 alg;
-       u32 flags;
-       u8 tx_seq[IW_ENCODE_SEQ_MAX_SIZE];
-       u8 rx_seq[IW_ENCODE_SEQ_MAX_SIZE];
-       u8 key_len;
-       u8 key[32];
+       u32 cipher;
+       u8 key[WLAN_MAX_KEY_LEN];
+       u8 seq[IW_ENCODE_SEQ_MAX_SIZE];
+       int key_len;
+       int seq_len;
 };
 
 #define IWM_RX_ID_HASH  0xff
@@ -186,10 +178,6 @@ struct iwm_key {
 #define IWM_STATUS_ASSOCIATING         3
 #define IWM_STATUS_ASSOCIATED          4
 
-#define IWM_RADIO_RFKILL_OFF           0
-#define IWM_RADIO_RFKILL_HW            1
-#define IWM_RADIO_RFKILL_SW            2
-
 struct iwm_tx_queue {
        int id;
        struct sk_buff_head queue;
@@ -223,7 +211,6 @@ struct iwm_priv {
        struct iwm_conf conf;
 
        unsigned long status;
-       unsigned long radio;
 
        struct list_head pending_notif;
        wait_queue_head_t notif_queue;
@@ -242,6 +229,7 @@ struct iwm_priv {
        u8 bssid[ETH_ALEN];
        u8 channel;
        u16 rate;
+       u32 txpower;
 
        struct iwm_sta_info sta_table[IWM_STA_TABLE_NUM];
        struct list_head bss_list;
@@ -276,7 +264,10 @@ struct iwm_priv {
        struct iwm_tx_queue txq[IWM_TX_QUEUES];
 
        struct iwm_key keys[IWM_NUM_KEYS];
-       struct iwm_key *default_key;
+       s8 default_key;
+
+       DECLARE_BITMAP(wifi_ntfy, WIFI_IF_NTFY_MAX);
+       wait_queue_head_t wifi_ntfy_queue;
 
        wait_queue_head_t mlme_queue;
 
@@ -289,7 +280,6 @@ struct iwm_priv {
        struct timer_list watchdog;
        struct work_struct reset_worker;
        struct mutex mutex;
-       struct rfkill *rfkill;
 
        char private[0] __attribute__((__aligned__(NETDEV_ALIGN)));
 };
index db2e5ee..19213e1 100644 (file)
@@ -396,6 +396,10 @@ enum {
        CALIBRATION_CMD_NUM,
 };
 
+#define IWM_CALIB_MAP_INIT_MSK         0xFFFF
+#define IWM_CALIB_MAP_PER_LMAC(m)      ((m & 0xFF0000) >> 16)
+#define IWM_CALIB_MAP_PER_UMAC(m)      ((m & 0xFF000000) >> 24)
+
 struct iwm_lmac_calib_hdr {
        u8 opcode;
        u8 first_grp;
index 8be206d..484f110 100644 (file)
 static struct iwm_conf def_iwm_conf = {
 
        .sdio_ior_timeout       = 5000,
-       .init_calib_map         = BIT(PHY_CALIBRATE_DC_CMD)     |
-                                 BIT(PHY_CALIBRATE_LO_CMD)     |
-                                 BIT(PHY_CALIBRATE_TX_IQ_CMD)  |
-                                 BIT(PHY_CALIBRATE_RX_IQ_CMD),
-       .periodic_calib_map     = BIT(PHY_CALIBRATE_DC_CMD)     |
+       .calib_map              = BIT(PHY_CALIBRATE_DC_CMD)     |
                                  BIT(PHY_CALIBRATE_LO_CMD)     |
                                  BIT(PHY_CALIBRATE_TX_IQ_CMD)  |
                                  BIT(PHY_CALIBRATE_RX_IQ_CMD)  |
@@ -191,6 +187,7 @@ int iwm_priv_init(struct iwm_priv *iwm)
        INIT_LIST_HEAD(&iwm->pending_notif);
        init_waitqueue_head(&iwm->notif_queue);
        init_waitqueue_head(&iwm->nonwifi_queue);
+       init_waitqueue_head(&iwm->wifi_ntfy_queue);
        init_waitqueue_head(&iwm->mlme_queue);
        memcpy(&iwm->conf, &def_iwm_conf, sizeof(struct iwm_conf));
        spin_lock_init(&iwm->tx_credit.lock);
@@ -229,7 +226,7 @@ int iwm_priv_init(struct iwm_priv *iwm)
        for (i = 0; i < IWM_NUM_KEYS; i++)
                memset(&iwm->keys[i], 0, sizeof(struct iwm_key));
 
-       iwm->default_key = NULL;
+       iwm->default_key = -1;
 
        init_timer(&iwm->watchdog);
        iwm->watchdog.function = iwm_watchdog;
@@ -518,13 +515,6 @@ static int iwm_channels_init(struct iwm_priv *iwm)
 {
        int ret;
 
-#ifdef CONFIG_IWM_B0_HW_SUPPORT
-       if (iwm->conf.hw_b0) {
-               IWM_INFO(iwm, "Workaround EEPROM channels for B0 hardware\n");
-               return 0;
-       }
-#endif
-
        ret = iwm_send_umac_channel_list(iwm);
        if (ret) {
                IWM_ERR(iwm, "Send channel list failed\n");
@@ -642,19 +632,10 @@ int __iwm_up(struct iwm_priv *iwm)
                }
        }
 
-       iwm->umac_profile = kmalloc(sizeof(struct iwm_umac_profile),
-                                   GFP_KERNEL);
-       if (!iwm->umac_profile) {
-               IWM_ERR(iwm, "Couldn't alloc memory for profile\n");
-               goto err_fw;
-       }
-
-       iwm_init_default_profile(iwm, iwm->umac_profile);
-
        ret = iwm_channels_init(iwm);
        if (ret < 0) {
                IWM_ERR(iwm, "Couldn't init channels\n");
-               goto err_profile;
+               goto err_fw;
        }
 
        /* Set the READY bit to indicate interface is brought up successfully */
@@ -662,10 +643,6 @@ int __iwm_up(struct iwm_priv *iwm)
 
        return 0;
 
- err_profile:
-       kfree(iwm->umac_profile);
-       iwm->umac_profile = NULL;
-
  err_fw:
        iwm_eeprom_exit(iwm);
 
@@ -704,11 +681,10 @@ int __iwm_down(struct iwm_priv *iwm)
        clear_bit(IWM_STATUS_READY, &iwm->status);
 
        iwm_eeprom_exit(iwm);
-       kfree(iwm->umac_profile);
-       iwm->umac_profile = NULL;
        iwm_bss_list_clean(iwm);
-
-       iwm->default_key = NULL;
+       iwm_init_default_profile(iwm, iwm->umac_profile);
+       iwm->umac_profile_active = false;
+       iwm->default_key = -1;
        iwm->core_enabled = 0;
 
        ret = iwm_bus_disable(iwm);
index aea5ccf..092d28a 100644 (file)
 #include <linux/netdevice.h>
 
 #include "iwm.h"
+#include "commands.h"
 #include "cfg80211.h"
 #include "debug.h"
 
 static int iwm_open(struct net_device *ndev)
 {
        struct iwm_priv *iwm = ndev_to_iwm(ndev);
-       int ret = 0;
-
-       if (!test_bit(IWM_RADIO_RFKILL_SW, &iwm->radio))
-               ret = iwm_up(iwm);
 
-       return ret;
+       return iwm_up(iwm);
 }
 
 static int iwm_stop(struct net_device *ndev)
 {
        struct iwm_priv *iwm = ndev_to_iwm(ndev);
-       int ret = 0;
-
-       if (!test_bit(IWM_RADIO_RFKILL_SW, &iwm->radio))
-               ret = iwm_down(iwm);
 
-       return ret;
+       return iwm_down(iwm);
 }
 
 /*
@@ -135,8 +128,20 @@ void *iwm_if_alloc(int sizeof_bus, struct device *dev,
        SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy));
        wdev->netdev = ndev;
 
+       iwm->umac_profile = kmalloc(sizeof(struct iwm_umac_profile),
+                                   GFP_KERNEL);
+       if (!iwm->umac_profile) {
+               dev_err(dev, "Couldn't alloc memory for profile\n");
+               goto out_profile;
+       }
+
+       iwm_init_default_profile(iwm, iwm->umac_profile);
+
        return iwm;
 
+ out_profile:
+       free_netdev(ndev);
+
  out_priv:
        iwm_priv_deinit(iwm);
 
@@ -152,6 +157,8 @@ void iwm_if_free(struct iwm_priv *iwm)
 
        free_netdev(iwm_to_ndev(iwm));
        iwm_priv_deinit(iwm);
+       kfree(iwm->umac_profile);
+       iwm->umac_profile = NULL;
        iwm_wdev_free(iwm);
 }
 
index d73cf96..3909477 100644 (file)
@@ -143,17 +143,18 @@ static int iwm_ntf_init_complete(struct iwm_priv *iwm, u8 *buf,
                                 unsigned long buf_size,
                                 struct iwm_wifi_cmd *cmd)
 {
+       struct wiphy *wiphy = iwm_to_wiphy(iwm);
        struct iwm_umac_notif_init_complete *init_complete =
                        (struct iwm_umac_notif_init_complete *)(buf);
        u16 status = le16_to_cpu(init_complete->status);
+       bool blocked = (status == UMAC_NTFY_INIT_COMPLETE_STATUS_ERR);
 
-       if (status == UMAC_NTFY_INIT_COMPLETE_STATUS_ERR) {
+       if (blocked)
                IWM_DBG_NTF(iwm, DBG, "Hardware rf kill is on (radio off)\n");
-               set_bit(IWM_RADIO_RFKILL_HW, &iwm->radio);
-       } else {
+       else
                IWM_DBG_NTF(iwm, DBG, "Hardware rf kill is off (radio on)\n");
-               clear_bit(IWM_RADIO_RFKILL_HW, &iwm->radio);
-       }
+
+       wiphy_rfkill_set_hw_state(wiphy, blocked);
 
        return 0;
 }
@@ -875,6 +876,7 @@ static int iwm_ntf_statistics(struct iwm_priv *iwm, u8 *buf,
                /* UMAC passes rate info multiplies by 2 */
                iwm->rate = max_rate >> 1;
        }
+       iwm->txpower = le32_to_cpu(stats->tx_power);
 
        wstats->status = 0;
 
@@ -922,13 +924,6 @@ static int iwm_ntf_eeprom_proxy(struct iwm_priv *iwm, u8 *buf,
        if ((hdr_offset + hdr_len) > IWM_EEPROM_LEN)
                return -EINVAL;
 
-#ifdef CONFIG_IWM_B0_HW_SUPPORT
-       if (hdr_offset == IWM_EEPROM_SKU_CAP_OFF) {
-               if (eeprom_proxy->buf[0] == 0xff)
-                       iwm->conf.hw_b0 = 1;
-       }
-#endif
-
        switch (hdr_type) {
        case IWM_UMAC_CMD_EEPROM_TYPE_READ:
                memcpy(iwm->eeprom + hdr_offset, eeprom_proxy->buf, hdr_len);
@@ -993,12 +988,17 @@ static int iwm_ntf_wifi_if_wrapper(struct iwm_priv *iwm, u8 *buf,
                        (struct iwm_umac_wifi_if *)cmd->buf.payload;
 
        IWM_DBG_NTF(iwm, DBG, "WIFI_IF_WRAPPER cmd is delivered to UMAC: "
-                   "oid is %d\n", hdr->oid);
+                   "oid is 0x%x\n", hdr->oid);
+
+       if (hdr->oid <= WIFI_IF_NTFY_MAX) {
+               set_bit(hdr->oid, &iwm->wifi_ntfy[0]);
+               wake_up_interruptible(&iwm->wifi_ntfy_queue);
+       } else
+               return -EINVAL;
 
        switch (hdr->oid) {
        case UMAC_WIFI_IF_CMD_SET_PROFILE:
                iwm->umac_profile_active = 1;
-               wake_up_interruptible(&iwm->mlme_queue);
                break;
        default:
                break;
@@ -1010,6 +1010,7 @@ static int iwm_ntf_wifi_if_wrapper(struct iwm_priv *iwm, u8 *buf,
 static int iwm_ntf_card_state(struct iwm_priv *iwm, u8 *buf,
                              unsigned long buf_size, struct iwm_wifi_cmd *cmd)
 {
+       struct wiphy *wiphy = iwm_to_wiphy(iwm);
        struct iwm_lmac_card_state *state = (struct iwm_lmac_card_state *)
                                (buf + sizeof(struct iwm_umac_wifi_in_hdr));
        u32 flags = le32_to_cpu(state->flags);
@@ -1018,10 +1019,7 @@ static int iwm_ntf_card_state(struct iwm_priv *iwm, u8 *buf,
                 flags & IWM_CARD_STATE_HW_DISABLED ? "ON" : "OFF",
                 flags & IWM_CARD_STATE_CTKILL_DISABLED ? "ON" : "OFF");
 
-       if (flags & IWM_CARD_STATE_HW_DISABLED)
-               set_bit(IWM_RADIO_RFKILL_HW, &iwm->radio);
-       else
-               clear_bit(IWM_RADIO_RFKILL_HW, &iwm->radio);
+       wiphy_rfkill_set_hw_state(wiphy, flags & IWM_CARD_STATE_HW_DISABLED);
 
        return 0;
 }
@@ -1368,7 +1366,7 @@ static void iwm_rx_process_packet(struct iwm_priv *iwm,
                ndev->stats.rx_packets++;
                ndev->stats.rx_bytes += skb->len;
 
-               if (netif_rx(skb) == NET_RX_DROP) {
+               if (netif_rx_ni(skb) == NET_RX_DROP) {
                        IWM_ERR(iwm, "Packet dropped\n");
                        ndev->stats.rx_dropped++;
                }
index 9166818..b93f620 100644 (file)
@@ -506,11 +506,7 @@ static struct sdio_driver iwm_sdio_driver = {
 
 static int __init iwm_sdio_init_module(void)
 {
-       int ret;
-
-       ret = sdio_register_driver(&iwm_sdio_driver);
-
-       return ret;
+       return sdio_register_driver(&iwm_sdio_driver);
 }
 
 static void __exit iwm_sdio_exit_module(void)
index 4a95cce..0af2a3c 100644 (file)
@@ -495,6 +495,8 @@ struct iwm_fw_alive_hdr {
 #define WIFI_DBG_IF_NTFY_COEX_HANDLE_ENVELOP           0xE8
 #define WIFI_DBG_IF_NTFY_COEX_HANDLE_RELEASE_ENVELOP   0xE9
 
+#define WIFI_IF_NTFY_MAX 0xff
+
 /* Notification structures */
 struct iwm_umac_notif_wifi_if {
        struct iwm_umac_wifi_in_hdr hdr;
index 584c94d..2e7eaf9 100644 (file)
@@ -82,6 +82,9 @@ static int iwm_wext_siwap(struct net_device *dev, struct iw_request_info *info,
                          struct sockaddr *ap_addr, char *extra)
 {
        struct iwm_priv *iwm = ndev_to_iwm(dev);
+       int ret;
+
+       IWM_DBG_WEXT(iwm, DBG, "Set BSSID: %pM\n", ap_addr->sa_data);
 
        if (iwm->conf.mode == UMAC_MODE_IBSS)
                return cfg80211_ibss_wext_siwap(dev, info, ap_addr, extra);
@@ -104,10 +107,25 @@ static int iwm_wext_siwap(struct net_device *dev, struct iw_request_info *info,
        }
 
        if (iwm->umac_profile_active) {
+               int i;
+
                if (!memcmp(&iwm->umac_profile->bssid[0], iwm->bssid, ETH_ALEN))
                        return 0;
 
-               iwm_invalidate_mlme_profile(iwm);
+               /*
+                * If we're clearing the BSSID, and we're associated,
+                * we have to clear the keys as they're no longer valid.
+                */
+               if (is_zero_ether_addr(ap_addr->sa_data)) {
+                       for (i = 0; i < IWM_NUM_KEYS; i++)
+                               iwm->keys[i].key_len = 0;
+               }
+
+               ret = iwm_invalidate_mlme_profile(iwm);
+               if (ret < 0) {
+                       IWM_ERR(iwm, "Couldn't invalidate profile\n");
+                       return ret;
+               }
        }
 
        if (iwm->umac_profile->ssid.ssid_len)
@@ -146,6 +164,8 @@ static int iwm_wext_siwessid(struct net_device *dev,
        size_t len = data->length;
        int ret;
 
+       IWM_DBG_WEXT(iwm, DBG, "Set ESSID: >%s<\n", ssid);
+
        if (iwm->conf.mode == UMAC_MODE_IBSS)
                return cfg80211_ibss_wext_siwessid(dev, info, data, ssid);
 
@@ -195,27 +215,6 @@ static int iwm_wext_giwessid(struct net_device *dev,
        return 0;
 }
 
-static struct iwm_key *
-iwm_key_init(struct iwm_priv *iwm, u8 key_idx, bool in_use,
-            struct iw_encode_ext *ext, u8 alg)
-{
-       struct iwm_key *key = &iwm->keys[key_idx];
-
-       memset(key, 0, sizeof(struct iwm_key));
-       memcpy(key->hdr.mac, ext->addr.sa_data, ETH_ALEN);
-       key->hdr.key_idx = key_idx;
-       if (is_broadcast_ether_addr(ext->addr.sa_data))
-               key->hdr.multicast = 1;
-
-       key->in_use = in_use;
-       key->flags = ext->ext_flags;
-       key->alg = alg;
-       key->key_len = ext->key_len;
-       memcpy(key->key, ext->key, ext->key_len);
-
-       return key;
-}
-
 static int iwm_wext_giwrate(struct net_device *dev,
                            struct iw_request_info *info,
                            struct iw_param *rate, char *extra)
@@ -227,184 +226,6 @@ static int iwm_wext_giwrate(struct net_device *dev,
        return 0;
 }
 
-static int iwm_wext_siwencode(struct net_device *dev,
-                             struct iw_request_info *info,
-                             struct iw_point *erq, char *key_buf)
-{
-       struct iwm_priv *iwm = ndev_to_iwm(dev);
-       struct iwm_key *uninitialized_var(key);
-       int idx, i, uninitialized_var(alg), remove = 0, ret;
-
-       IWM_DBG_WEXT(iwm, DBG, "key len: %d\n", erq->length);
-       IWM_DBG_WEXT(iwm, DBG, "flags: 0x%x\n", erq->flags);
-
-       if (!iwm->umac_profile) {
-               IWM_ERR(iwm, "UMAC profile not allocated yet\n");
-               return -ENODEV;
-       }
-
-       if (erq->length == WLAN_KEY_LEN_WEP40) {
-               alg = UMAC_CIPHER_TYPE_WEP_40;
-               iwm->umac_profile->sec.ucast_cipher = UMAC_CIPHER_TYPE_WEP_40;
-               iwm->umac_profile->sec.mcast_cipher = UMAC_CIPHER_TYPE_WEP_40;
-       } else if (erq->length == WLAN_KEY_LEN_WEP104) {
-               alg = UMAC_CIPHER_TYPE_WEP_104;
-               iwm->umac_profile->sec.ucast_cipher = UMAC_CIPHER_TYPE_WEP_104;
-               iwm->umac_profile->sec.mcast_cipher = UMAC_CIPHER_TYPE_WEP_104;
-       }
-
-       if (erq->flags & IW_ENCODE_RESTRICTED)
-               iwm->umac_profile->sec.auth_type = UMAC_AUTH_TYPE_LEGACY_PSK;
-       else
-               iwm->umac_profile->sec.auth_type = UMAC_AUTH_TYPE_OPEN;
-
-       idx = erq->flags & IW_ENCODE_INDEX;
-       if (idx == 0) {
-               if (iwm->default_key)
-                       for (i = 0; i < IWM_NUM_KEYS; i++) {
-                               if (iwm->default_key == &iwm->keys[i]) {
-                                       idx = i;
-                                       break;
-                               }
-                       }
-               else
-                       iwm->default_key = &iwm->keys[idx];
-       } else if (idx < 1 || idx > 4) {
-               return -EINVAL;
-       } else
-               idx--;
-
-       if (erq->flags & IW_ENCODE_DISABLED)
-               remove = 1;
-       else if (erq->length == 0) {
-               if (!iwm->keys[idx].in_use)
-                       return -EINVAL;
-               iwm->default_key = &iwm->keys[idx];
-       }
-
-       if (erq->length) {
-               key = &iwm->keys[idx];
-               memset(key, 0, sizeof(struct iwm_key));
-               memset(key->hdr.mac, 0xff, ETH_ALEN);
-               key->hdr.key_idx = idx;
-               key->hdr.multicast = 1;
-               key->in_use = !remove;
-               key->alg = alg;
-               key->key_len = erq->length;
-               memcpy(key->key, key_buf, erq->length);
-
-               IWM_DBG_WEXT(iwm, DBG, "Setting key %d, default: %d\n",
-                            idx, !!iwm->default_key);
-       }
-
-       if (remove) {
-               if ((erq->flags & IW_ENCODE_NOKEY) || (erq->length == 0)) {
-                       int j;
-                       for (j = 0; j < IWM_NUM_KEYS; j++)
-                               if (iwm->keys[j].in_use) {
-                                       struct iwm_key *k = &iwm->keys[j];
-
-                                       k->in_use = 0;
-                                       ret = iwm_set_key(iwm, remove, 0, k);
-                                       if (ret < 0)
-                                               return ret;
-                               }
-
-                       iwm->umac_profile->sec.ucast_cipher =
-                                                       UMAC_CIPHER_TYPE_NONE;
-                       iwm->umac_profile->sec.mcast_cipher =
-                                                       UMAC_CIPHER_TYPE_NONE;
-                       iwm->umac_profile->sec.auth_type =
-                                                       UMAC_AUTH_TYPE_OPEN;
-
-                       return 0;
-               } else {
-                       key->in_use = 0;
-                       return iwm_set_key(iwm, remove, 0, key);
-               }
-       }
-
-       /*
-        * If we havent set a profile yet, we cant set keys.
-        * Keys will be pushed after we're associated.
-        */
-       if (!iwm->umac_profile_active)
-               return 0;
-
-       /*
-        * If there is a current active profile, but no
-        * default key, it's not worth trying to associate again.
-        */
-       if (!iwm->default_key)
-               return 0;
-
-       /*
-        * Here we have an active profile, but a key setting changed.
-        * We thus have to invalidate the current profile, and push the
-        * new one. Keys will be pushed when association takes place.
-        */
-       ret = iwm_invalidate_mlme_profile(iwm);
-       if (ret < 0) {
-               IWM_ERR(iwm, "Couldn't invalidate profile\n");
-               return ret;
-       }
-
-       return iwm_send_mlme_profile(iwm);
-}
-
-static int iwm_wext_giwencode(struct net_device *dev,
-                             struct iw_request_info *info,
-                             struct iw_point *erq, char *key)
-{
-       struct iwm_priv *iwm = ndev_to_iwm(dev);
-       int idx, i;
-
-       idx = erq->flags & IW_ENCODE_INDEX;
-       if (idx < 1 || idx > 4) {
-               idx = -1;
-               if (!iwm->default_key) {
-                       erq->length = 0;
-                       erq->flags |= IW_ENCODE_NOKEY;
-                       return 0;
-               } else
-                       for (i = 0; i < IWM_NUM_KEYS; i++) {
-                               if (iwm->default_key == &iwm->keys[i]) {
-                                       idx = i;
-                                       break;
-                               }
-                       }
-               if (idx < 0)
-                       return -EINVAL;
-       } else
-               idx--;
-
-       erq->flags = idx + 1;
-
-       if (!iwm->keys[idx].in_use) {
-               erq->length = 0;
-               erq->flags |= IW_ENCODE_DISABLED;
-               return 0;
-       }
-
-       memcpy(key, iwm->keys[idx].key,
-              min_t(int, erq->length, iwm->keys[idx].key_len));
-       erq->length = iwm->keys[idx].key_len;
-       erq->flags |= IW_ENCODE_ENABLED;
-
-       if (iwm->umac_profile->mode == UMAC_MODE_BSS) {
-               switch (iwm->umac_profile->sec.auth_type) {
-               case UMAC_AUTH_TYPE_OPEN:
-                       erq->flags |= IW_ENCODE_OPEN;
-                       break;
-               default:
-                       erq->flags |= IW_ENCODE_RESTRICTED;
-                       break;
-               }
-       }
-
-       return 0;
-}
-
 static int iwm_set_wpa_version(struct iwm_priv *iwm, u8 wpa_version)
 {
        if (wpa_version & IW_AUTH_WPA_VERSION_WPA2)
@@ -417,53 +238,12 @@ static int iwm_set_wpa_version(struct iwm_priv *iwm, u8 wpa_version)
        return 0;
 }
 
-static int iwm_wext_siwpower(struct net_device *dev,
-                            struct iw_request_info *info,
-                            struct iw_param *wrq, char *extra)
-{
-       struct iwm_priv *iwm = ndev_to_iwm(dev);
-       u32 power_index;
-
-       if (wrq->disabled) {
-               power_index = IWM_POWER_INDEX_MIN;
-               goto set;
-       } else
-               power_index = IWM_POWER_INDEX_DEFAULT;
-
-       switch (wrq->flags & IW_POWER_MODE) {
-       case IW_POWER_ON:
-       case IW_POWER_MODE:
-       case IW_POWER_ALL_R:
-               break;
-       default:
-               return -EINVAL;
-       }
-
- set:
-       if (power_index == iwm->conf.power_index)
-               return 0;
-
-       iwm->conf.power_index = power_index;
-
-       return iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX,
-                                      CFG_POWER_INDEX, iwm->conf.power_index);
-}
-
-static int iwm_wext_giwpower(struct net_device *dev,
-                            struct iw_request_info *info,
-                            union iwreq_data *wrqu, char *extra)
-{
-       struct iwm_priv *iwm = ndev_to_iwm(dev);
-
-       wrqu->power.disabled = (iwm->conf.power_index == IWM_POWER_INDEX_MIN);
-
-       return 0;
-}
-
 static int iwm_set_key_mgt(struct iwm_priv *iwm, u8 key_mgt)
 {
        u8 *auth_type = &iwm->umac_profile->sec.auth_type;
 
+       IWM_DBG_WEXT(iwm, DBG, "key_mgt: 0x%x\n", key_mgt);
+
        if (key_mgt == IW_AUTH_KEY_MGMT_802_1X)
                *auth_type = UMAC_AUTH_TYPE_8021X;
        else if (key_mgt == IW_AUTH_KEY_MGMT_PSK) {
@@ -513,6 +293,8 @@ static int iwm_set_auth_alg(struct iwm_priv *iwm, u8 auth_alg)
 {
        u8 *auth_type = &iwm->umac_profile->sec.auth_type;
 
+       IWM_DBG_WEXT(iwm, DBG, "auth_alg: 0x%x\n", auth_alg);
+
        switch (auth_alg) {
        case IW_AUTH_ALG_OPEN_SYSTEM:
                *auth_type = UMAC_AUTH_TYPE_OPEN;
@@ -524,6 +306,7 @@ static int iwm_set_auth_alg(struct iwm_priv *iwm, u8 auth_alg)
                                return -EINVAL;
                        *auth_type = UMAC_AUTH_TYPE_RSNA_PSK;
                } else {
+                       IWM_DBG_WEXT(iwm, DBG, "WEP shared key\n");
                        *auth_type = UMAC_AUTH_TYPE_LEGACY_PSK;
                }
                break;
@@ -586,75 +369,6 @@ static int iwm_wext_giwauth(struct net_device *dev,
        return 0;
 }
 
-static int iwm_wext_siwencodeext(struct net_device *dev,
-                                struct iw_request_info *info,
-                                struct iw_point *erq, char *extra)
-{
-       struct iwm_priv *iwm = ndev_to_iwm(dev);
-       struct iwm_key *key;
-       struct iw_encode_ext *ext = (struct iw_encode_ext *) extra;
-       int uninitialized_var(alg), idx, i, remove = 0;
-
-       IWM_DBG_WEXT(iwm, DBG, "alg: 0x%x\n", ext->alg);
-       IWM_DBG_WEXT(iwm, DBG, "key len: %d\n", ext->key_len);
-       IWM_DBG_WEXT(iwm, DBG, "ext_flags: 0x%x\n", ext->ext_flags);
-       IWM_DBG_WEXT(iwm, DBG, "flags: 0x%x\n", erq->flags);
-       IWM_DBG_WEXT(iwm, DBG, "length: 0x%x\n", erq->length);
-
-       switch (ext->alg) {
-       case IW_ENCODE_ALG_NONE:
-               remove = 1;
-               break;
-       case IW_ENCODE_ALG_WEP:
-               if (ext->key_len == WLAN_KEY_LEN_WEP40)
-                       alg = UMAC_CIPHER_TYPE_WEP_40;
-               else if (ext->key_len == WLAN_KEY_LEN_WEP104)
-                       alg = UMAC_CIPHER_TYPE_WEP_104;
-               else {
-                       IWM_ERR(iwm, "Invalid key length: %d\n", ext->key_len);
-                       return -EINVAL;
-               }
-
-               break;
-       case IW_ENCODE_ALG_TKIP:
-               alg = UMAC_CIPHER_TYPE_TKIP;
-               break;
-       case IW_ENCODE_ALG_CCMP:
-               alg = UMAC_CIPHER_TYPE_CCMP;
-               break;
-       default:
-               return -EOPNOTSUPP;
-       }
-
-       idx = erq->flags & IW_ENCODE_INDEX;
-
-       if (idx == 0) {
-               if (iwm->default_key)
-                       for (i = 0; i < IWM_NUM_KEYS; i++) {
-                               if (iwm->default_key == &iwm->keys[i]) {
-                                       idx = i;
-                                       break;
-                               }
-                       }
-       } else if (idx < 1 || idx > 4) {
-               return -EINVAL;
-       } else
-               idx--;
-
-       if (erq->flags & IW_ENCODE_DISABLED)
-               remove = 1;
-       else if ((erq->length == 0) ||
-                (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY)) {
-               iwm->default_key = &iwm->keys[idx];
-               if (iwm->umac_profile_active && ext->alg == IW_ENCODE_ALG_WEP)
-                       return iwm_set_tx_key(iwm, idx);
-       }
-
-       key = iwm_key_init(iwm, idx, !remove, ext, alg);
-
-       return iwm_set_key(iwm, remove, !iwm->default_key, key);
-}
-
 static const iw_handler iwm_handlers[] =
 {
        (iw_handler) NULL,                              /* SIOCSIWCOMMIT */
@@ -695,21 +409,21 @@ static const iw_handler iwm_handlers[] =
        (iw_handler) cfg80211_wext_giwrts,              /* SIOCGIWRTS */
        (iw_handler) cfg80211_wext_siwfrag,             /* SIOCSIWFRAG */
        (iw_handler) cfg80211_wext_giwfrag,             /* SIOCGIWFRAG */
-       (iw_handler) NULL,                              /* SIOCSIWTXPOW */
-       (iw_handler) NULL,                              /* SIOCGIWTXPOW */
+       (iw_handler) cfg80211_wext_siwtxpower,          /* SIOCSIWTXPOW */
+       (iw_handler) cfg80211_wext_giwtxpower,          /* SIOCGIWTXPOW */
        (iw_handler) NULL,                              /* SIOCSIWRETRY */
        (iw_handler) NULL,                              /* SIOCGIWRETRY */
-       (iw_handler) iwm_wext_siwencode,                /* SIOCSIWENCODE */
-       (iw_handler) iwm_wext_giwencode,                /* SIOCGIWENCODE */
-       (iw_handler) iwm_wext_siwpower,                 /* SIOCSIWPOWER */
-       (iw_handler) iwm_wext_giwpower,                 /* SIOCGIWPOWER */
+       (iw_handler) cfg80211_wext_siwencode,           /* SIOCSIWENCODE */
+       (iw_handler) cfg80211_wext_giwencode,           /* SIOCGIWENCODE */
+       (iw_handler) cfg80211_wext_siwpower,            /* SIOCSIWPOWER */
+       (iw_handler) cfg80211_wext_giwpower,            /* SIOCGIWPOWER */
        (iw_handler) NULL,                              /* -- hole -- */
        (iw_handler) NULL,                              /* -- hole -- */
        (iw_handler) NULL,                              /* SIOCSIWGENIE */
        (iw_handler) NULL,                              /* SIOCGIWGENIE */
        (iw_handler) iwm_wext_siwauth,                  /* SIOCSIWAUTH */
        (iw_handler) iwm_wext_giwauth,                  /* SIOCGIWAUTH */
-       (iw_handler) iwm_wext_siwencodeext,             /* SIOCSIWENCODEEXT */
+       (iw_handler) cfg80211_wext_siwencodeext,        /* SIOCSIWENCODEEXT */
        (iw_handler) NULL,                              /* SIOCGIWENCODEEXT */
        (iw_handler) NULL,                              /* SIOCSIWPMKSA */
        (iw_handler) NULL,                              /* -- hole -- */
index b9b3741..fbf2649 100644 (file)
@@ -1368,11 +1368,17 @@ static int assoc_helper_wpa_keys(struct lbs_private *priv,
        if (ret)
                goto out;
 
+       memcpy(&priv->wpa_unicast_key, &assoc_req->wpa_unicast_key,
+                       sizeof(struct enc_key));
+
        if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags)) {
                clear_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags);
 
                ret = lbs_cmd_802_11_key_material(priv, CMD_ACT_SET, assoc_req);
                assoc_req->flags = flags;
+
+               memcpy(&priv->wpa_mcast_key, &assoc_req->wpa_mcast_key,
+                               sizeof(struct enc_key));
        }
 
 out:
index f9ec69e..578c697 100644 (file)
@@ -260,7 +260,6 @@ struct lbs_private {
        u16 psmode;             /* Wlan802_11PowermodeCAM=disable
                                   Wlan802_11PowermodeMAX_PSP=enable */
        u32 psstate;
-       char ps_supported;
        u8 needtowakeup;
 
        struct assoc_request * pending_assoc_req;
index 2a5b083..f658fd6 100644 (file)
@@ -933,9 +933,6 @@ static int if_cs_probe(struct pcmcia_device *p_dev)
                goto out3;
        }
 
-       /* The firmware for the CF card supports powersave */
-       priv->ps_supported = 1;
-
        ret = 0;
        goto out;
 
index 8cdb88c..485a8d4 100644 (file)
@@ -1039,9 +1039,6 @@ 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);
 
@@ -1096,11 +1093,11 @@ static void if_sdio_remove(struct sdio_func *func)
                        lbs_pr_alert("CMD_FUNC_SHUTDOWN cmd failed\n");
        }
 
-       card->priv->surpriseremoved = 1;
 
        lbs_deb_sdio("call remove card\n");
        lbs_stop_card(card->priv);
        lbs_remove_card(card->priv);
+       card->priv->surpriseremoved = 1;
 
        flush_workqueue(card->workqueue);
        destroy_workqueue(card->workqueue);
index 6564282..963c201 100644 (file)
@@ -737,7 +737,7 @@ static int if_spi_c2h_data(struct if_spi_card *card)
                goto out;
        } else if (len > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE) {
                lbs_pr_err("%s: error: card has %d bytes of data, but "
-                          "our maximum skb size is %lu\n",
+                          "our maximum skb size is %zu\n",
                           __func__, len, MRVDRV_ETH_RX_PACKET_BUFFER_SIZE);
                err = -EINVAL;
                goto out;
@@ -1118,7 +1118,6 @@ static int __devinit if_spi_probe(struct spi_device *spi)
        priv->card = card;
        priv->hw_host_to_card = if_spi_host_to_card;
        priv->fw_ready = 1;
-       priv->ps_supported = 1;
 
        /* Initialize interrupt handling stuff. */
        card->run_thread = 1;
@@ -1171,12 +1170,13 @@ static int __devexit libertas_spi_remove(struct spi_device *spi)
 
        lbs_deb_spi("libertas_spi_remove\n");
        lbs_deb_enter(LBS_DEB_SPI);
-       priv->surpriseremoved = 1;
 
        lbs_stop_card(priv);
+       lbs_remove_card(priv); /* will call free_netdev */
+
+       priv->surpriseremoved = 1;
        free_irq(spi->irq, card);
        if_spi_terminate_spi_thread(card);
-       lbs_remove_card(priv); /* will call free_netdev */
        if (card->pdata->teardown)
                card->pdata->teardown(spi);
        free_if_spi_card(card);
index 1844c5a..92bc8c5 100644 (file)
@@ -181,13 +181,14 @@ static void if_usb_setup_firmware(struct lbs_private *priv)
        wake_method.action = cpu_to_le16(CMD_ACT_GET);
        if (lbs_cmd_with_response(priv, CMD_802_11_FW_WAKE_METHOD, &wake_method)) {
                lbs_pr_info("Firmware does not seem to support PS mode\n");
+               priv->fwcapinfo &= ~FW_CAPINFO_PS;
        } else {
                if (le16_to_cpu(wake_method.method) == CMD_WAKE_METHOD_COMMAND_INT) {
                        lbs_deb_usb("Firmware seems to support PS with wake-via-command\n");
-                       priv->ps_supported = 1;
                } else {
                        /* The versions which boot up this way don't seem to
                           work even if we set it to the command interrupt */
+                       priv->fwcapinfo &= ~FW_CAPINFO_PS;
                        lbs_pr_info("Firmware doesn't wake via command interrupt; disabling PS mode\n");
                }
        }
index 8bc1907..e96451c 100644 (file)
@@ -712,7 +712,7 @@ static int lbs_set_power(struct net_device *dev, struct iw_request_info *info,
 
        lbs_deb_enter(LBS_DEB_WEXT);
 
-       if (!priv->ps_supported) {
+       if (!(priv->fwcapinfo & FW_CAPINFO_PS)) {
                if (vwrq->disabled)
                        return 0;
                else
index 10a99e2..4872345 100644 (file)
@@ -503,7 +503,8 @@ int lbtf_rx(struct lbtf_private *priv, struct sk_buff *skb)
                skb_reserve(skb, 2);
        }
 
-       ieee80211_rx_irqsafe(priv->hw, skb, &stats);
+       memcpy(IEEE80211_SKB_RXCB(skb), &stats, sizeof(stats));
+       ieee80211_rx_irqsafe(priv->hw, skb);
        return 0;
 }
 EXPORT_SYMBOL_GPL(lbtf_rx);
index 7916ca3..e9b5442 100644 (file)
@@ -15,6 +15,8 @@
 
 #include <linux/list.h>
 #include <linux/spinlock.h>
+#include <net/dst.h>
+#include <net/xfrm.h>
 #include <net/mac80211.h>
 #include <net/ieee80211_radiotap.h>
 #include <linux/if_arp.h>
@@ -314,7 +316,7 @@ static int hwsim_mon_xmit(struct sk_buff *skb, struct net_device *dev)
 {
        /* TODO: allow packet injection */
        dev_kfree_skb(skb);
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 
@@ -409,6 +411,13 @@ static bool mac80211_hwsim_tx_frame(struct ieee80211_hw *hw,
        if (data->ps != PS_DISABLED)
                hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM);
 
+       /* release the skb's source info */
+       skb_orphan(skb);
+       skb_dst_drop(skb);
+       skb->mark = 0;
+       secpath_reset(skb);
+       nf_reset(skb);
+
        /* Copy skb to all enabled radios that are on the current frequency */
        spin_lock(&hwsim_radio_lock);
        list_for_each_entry(data2, &hwsim_radios, list) {
@@ -430,7 +439,8 @@ static bool mac80211_hwsim_tx_frame(struct ieee80211_hw *hw,
                if (memcmp(hdr->addr1, data2->hw->wiphy->perm_addr,
                           ETH_ALEN) == 0)
                        ack = true;
-               ieee80211_rx_irqsafe(data2->hw, nskb, &rx_status);
+               memcpy(IEEE80211_SKB_RXCB(nskb), &rx_status, sizeof(rx_status));
+               ieee80211_rx_irqsafe(data2->hw, nskb);
        }
        spin_unlock(&hwsim_radio_lock);
 
@@ -690,6 +700,74 @@ static int mac80211_hwsim_conf_tx(
        return 0;
 }
 
+#ifdef CONFIG_NL80211_TESTMODE
+/*
+ * This section contains example code for using netlink
+ * attributes with the testmode command in nl80211.
+ */
+
+/* These enums need to be kept in sync with userspace */
+enum hwsim_testmode_attr {
+       __HWSIM_TM_ATTR_INVALID = 0,
+       HWSIM_TM_ATTR_CMD       = 1,
+       HWSIM_TM_ATTR_PS        = 2,
+
+       /* keep last */
+       __HWSIM_TM_ATTR_AFTER_LAST,
+       HWSIM_TM_ATTR_MAX       = __HWSIM_TM_ATTR_AFTER_LAST - 1
+};
+
+enum hwsim_testmode_cmd {
+       HWSIM_TM_CMD_SET_PS             = 0,
+       HWSIM_TM_CMD_GET_PS             = 1,
+};
+
+static const struct nla_policy hwsim_testmode_policy[HWSIM_TM_ATTR_MAX + 1] = {
+       [HWSIM_TM_ATTR_CMD] = { .type = NLA_U32 },
+       [HWSIM_TM_ATTR_PS] = { .type = NLA_U32 },
+};
+
+static int hwsim_fops_ps_write(void *dat, u64 val);
+
+static int mac80211_hwsim_testmode_cmd(struct ieee80211_hw *hw,
+                                      void *data, int len)
+{
+       struct mac80211_hwsim_data *hwsim = hw->priv;
+       struct nlattr *tb[HWSIM_TM_ATTR_MAX + 1];
+       struct sk_buff *skb;
+       int err, ps;
+
+       err = nla_parse(tb, HWSIM_TM_ATTR_MAX, data, len,
+                       hwsim_testmode_policy);
+       if (err)
+               return err;
+
+       if (!tb[HWSIM_TM_ATTR_CMD])
+               return -EINVAL;
+
+       switch (nla_get_u32(tb[HWSIM_TM_ATTR_CMD])) {
+       case HWSIM_TM_CMD_SET_PS:
+               if (!tb[HWSIM_TM_ATTR_PS])
+                       return -EINVAL;
+               ps = nla_get_u32(tb[HWSIM_TM_ATTR_PS]);
+               return hwsim_fops_ps_write(hwsim, ps);
+       case HWSIM_TM_CMD_GET_PS:
+               skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy,
+                                               nla_total_size(sizeof(u32)));
+               if (!skb)
+                       return -ENOMEM;
+               NLA_PUT_U32(skb, HWSIM_TM_ATTR_PS, hwsim->ps);
+               return cfg80211_testmode_reply(skb);
+       default:
+               return -EOPNOTSUPP;
+       }
+
+ nla_put_failure:
+       kfree_skb(skb);
+       return -ENOBUFS;
+}
+#endif
+
 static const struct ieee80211_ops mac80211_hwsim_ops =
 {
        .tx = mac80211_hwsim_tx,
@@ -703,6 +781,7 @@ static const struct ieee80211_ops mac80211_hwsim_ops =
        .sta_notify = mac80211_hwsim_sta_notify,
        .set_tim = mac80211_hwsim_set_tim,
        .conf_tx = mac80211_hwsim_conf_tx,
+       CFG80211_TESTMODE_CMD(mac80211_hwsim_testmode_cmd)
 };
 
 
index a263d5c..b9eded8 100644 (file)
@@ -1047,7 +1047,8 @@ static int rxq_process(struct ieee80211_hw *hw, int index, int limit)
                status.flag = 0;
                status.band = IEEE80211_BAND_2GHZ;
                status.freq = ieee80211_channel_to_frequency(rx_desc->channel);
-               ieee80211_rx_irqsafe(hw, skb, &status);
+               memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status));
+               ieee80211_rx_irqsafe(hw, skb);
 
                processed++;
        }
index d63c899..712f26e 100644 (file)
@@ -1047,7 +1047,7 @@ static int netwave_start_xmit(struct sk_buff *skb, struct net_device *dev) {
     }
     dev_kfree_skb(skb);
     
-    return 0;
+    return NETDEV_TX_OK;
 } /* netwave_start_xmit */
 
 /*
index 44411eb..83b635f 100644 (file)
@@ -1,6 +1,7 @@
 config HERMES
        tristate "Hermes chipset 802.11b support (Orinoco/Prism2/Symbol)"
        depends on (PPC_PMAC || PCI || PCMCIA) && WLAN_80211
+       depends on CFG80211
        select WIRELESS_EXT
        select FW_LOADER
        select CRYPTO
index 1fc7409..9abd632 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Makefile for the orinoco wireless device drivers.
 #
-orinoco-objs := main.o fw.o hw.o mic.o scan.o wext.o hermes_dld.o hermes.o
+orinoco-objs := main.o fw.o hw.o mic.o scan.o wext.o hermes_dld.o hermes.o cfg.o
 
 obj-$(CONFIG_HERMES)           += orinoco.o
 obj-$(CONFIG_PCMCIA_HERMES)    += orinoco_cs.o
index 8c4065f..c60df2c 100644 (file)
@@ -27,6 +27,7 @@
 struct airport {
        struct macio_dev *mdev;
        void __iomem *vaddr;
+       unsigned int irq;
        int irq_requested;
        int ndev_registered;
 };
@@ -34,8 +35,9 @@ struct airport {
 static int
 airport_suspend(struct macio_dev *mdev, pm_message_t state)
 {
-       struct net_device *dev = dev_get_drvdata(&mdev->ofdev.dev);
-       struct orinoco_private *priv = netdev_priv(dev);
+       struct orinoco_private *priv = dev_get_drvdata(&mdev->ofdev.dev);
+       struct net_device *dev = priv->ndev;
+       struct airport *card = priv->card;
        unsigned long flags;
        int err;
 
@@ -48,18 +50,10 @@ airport_suspend(struct macio_dev *mdev, pm_message_t state)
                return 0;
        }
 
-       err = __orinoco_down(dev);
-       if (err)
-               printk(KERN_WARNING "%s: PBOOK_SLEEP_NOW: Error %d downing interface\n",
-                      dev->name, err);
-
-       netif_device_detach(dev);
-
-       priv->hw_unavailable++;
-
+       orinoco_down(priv);
        orinoco_unlock(priv, &flags);
 
-       disable_irq(dev->irq);
+       disable_irq(card->irq);
        pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE,
                          macio_get_of_node(mdev), 0, 0);
 
@@ -69,8 +63,9 @@ airport_suspend(struct macio_dev *mdev, pm_message_t state)
 static int
 airport_resume(struct macio_dev *mdev)
 {
-       struct net_device *dev = dev_get_drvdata(&mdev->ofdev.dev);
-       struct orinoco_private *priv = netdev_priv(dev);
+       struct orinoco_private *priv = dev_get_drvdata(&mdev->ofdev.dev);
+       struct net_device *dev = priv->ndev;
+       struct airport *card = priv->card;
        unsigned long flags;
        int err;
 
@@ -80,47 +75,27 @@ airport_resume(struct macio_dev *mdev)
                          macio_get_of_node(mdev), 0, 1);
        msleep(200);
 
-       enable_irq(dev->irq);
-
-       err = orinoco_reinit_firmware(dev);
-       if (err) {
-               printk(KERN_ERR "%s: Error %d re-initializing firmware on PBOOK_WAKE\n",
-                      dev->name, err);
-               return 0;
-       }
+       enable_irq(card->irq);
 
        spin_lock_irqsave(&priv->lock, flags);
-
-       netif_device_attach(dev);
-
-       priv->hw_unavailable--;
-
-       if (priv->open && (!priv->hw_unavailable)) {
-               err = __orinoco_up(dev);
-               if (err)
-                       printk(KERN_ERR "%s: Error %d restarting card on PBOOK_WAKE\n",
-                              dev->name, err);
-       }
-
-
+       err = orinoco_up(priv);
        spin_unlock_irqrestore(&priv->lock, flags);
 
-       return 0;
+       return err;
 }
 
 static int
 airport_detach(struct macio_dev *mdev)
 {
-       struct net_device *dev = dev_get_drvdata(&mdev->ofdev.dev);
-       struct orinoco_private *priv = netdev_priv(dev);
+       struct orinoco_private *priv = dev_get_drvdata(&mdev->ofdev.dev);
        struct airport *card = priv->card;
 
        if (card->ndev_registered)
-               unregister_netdev(dev);
+               orinoco_if_del(priv);
        card->ndev_registered = 0;
 
        if (card->irq_requested)
-               free_irq(dev->irq, dev);
+               free_irq(card->irq, priv);
        card->irq_requested = 0;
 
        if (card->vaddr)
@@ -134,7 +109,7 @@ airport_detach(struct macio_dev *mdev)
        ssleep(1);
 
        macio_set_drvdata(mdev, NULL);
-       free_orinocodev(dev);
+       free_orinocodev(priv);
 
        return 0;
 }
@@ -146,7 +121,6 @@ static int airport_hard_reset(struct orinoco_private *priv)
         * re-initialize properly, it falls in a screaming heap
         * shortly afterwards. */
 #if 0
-       struct net_device *dev = priv->ndev;
        struct airport *card = priv->card;
 
        /* Vitally important.  If we don't do this it seems we get an
@@ -154,7 +128,7 @@ static int airport_hard_reset(struct orinoco_private *priv)
         * hw_unavailable is already set it doesn't get ACKed, we get
         * into an interrupt loop and the PMU decides to turn us
         * off. */
-       disable_irq(dev->irq);
+       disable_irq(card->irq);
 
        pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE,
                          macio_get_of_node(card->mdev), 0, 0);
@@ -163,7 +137,7 @@ static int airport_hard_reset(struct orinoco_private *priv)
                          macio_get_of_node(card->mdev), 0, 1);
        ssleep(1);
 
-       enable_irq(dev->irq);
+       enable_irq(card->irq);
        ssleep(1);
 #endif
 
@@ -174,7 +148,6 @@ static int
 airport_attach(struct macio_dev *mdev, const struct of_device_id *match)
 {
        struct orinoco_private *priv;
-       struct net_device *dev;
        struct airport *card;
        unsigned long phys_addr;
        hermes_t *hw;
@@ -185,33 +158,29 @@ airport_attach(struct macio_dev *mdev, const struct of_device_id *match)
        }
 
        /* Allocate space for private device-specific data */
-       dev = alloc_orinocodev(sizeof(*card), &mdev->ofdev.dev,
-                              airport_hard_reset, NULL);
-       if (!dev) {
+       priv = alloc_orinocodev(sizeof(*card), &mdev->ofdev.dev,
+                               airport_hard_reset, NULL);
+       if (!priv) {
                printk(KERN_ERR PFX "Cannot allocate network device\n");
                return -ENODEV;
        }
-       priv = netdev_priv(dev);
        card = priv->card;
 
        hw = &priv->hw;
        card->mdev = mdev;
 
-       if (macio_request_resource(mdev, 0, "airport")) {
+       if (macio_request_resource(mdev, 0, DRIVER_NAME)) {
                printk(KERN_ERR PFX "can't request IO resource !\n");
-               free_orinocodev(dev);
+               free_orinocodev(priv);
                return -EBUSY;
        }
 
-       SET_NETDEV_DEV(dev, &mdev->ofdev.dev);
-
-       macio_set_drvdata(mdev, dev);
+       macio_set_drvdata(mdev, priv);
 
        /* Setup interrupts & base address */
-       dev->irq = macio_irq(mdev, 0);
+       card->irq = macio_irq(mdev, 0);
        phys_addr = macio_resource_start(mdev, 0);  /* Physical address */
        printk(KERN_DEBUG PFX "Physical address %lx\n", phys_addr);
-       dev->base_addr = phys_addr;
        card->vaddr = ioremap(phys_addr, AIRPORT_IO_LEN);
        if (!card->vaddr) {
                printk(KERN_ERR PFX "ioremap() failed\n");
@@ -228,18 +197,23 @@ airport_attach(struct macio_dev *mdev, const struct of_device_id *match)
        /* Reset it before we get the interrupt */
        hermes_init(hw);
 
-       if (request_irq(dev->irq, orinoco_interrupt, 0, dev->name, dev)) {
-               printk(KERN_ERR PFX "Couldn't get IRQ %d\n", dev->irq);
+       if (request_irq(card->irq, orinoco_interrupt, 0, DRIVER_NAME, priv)) {
+               printk(KERN_ERR PFX "Couldn't get IRQ %d\n", card->irq);
                goto failed;
        }
        card->irq_requested = 1;
 
-       /* Tell the stack we exist */
-       if (register_netdev(dev) != 0) {
-               printk(KERN_ERR PFX "register_netdev() failed\n");
+       /* Initialise the main driver */
+       if (orinoco_init(priv) != 0) {
+               printk(KERN_ERR PFX "orinoco_init() failed\n");
+               goto failed;
+       }
+
+       /* Register an interface with the stack */
+       if (orinoco_if_add(priv, phys_addr, card->irq) != 0) {
+               printk(KERN_ERR PFX "orinoco_if_add() failed\n");
                goto failed;
        }
-       printk(KERN_DEBUG PFX "Card registered for interface %s\n", dev->name);
        card->ndev_registered = 1;
        return 0;
  failed:
diff --git a/drivers/net/wireless/orinoco/cfg.c b/drivers/net/wireless/orinoco/cfg.c
new file mode 100644 (file)
index 0000000..1a87d3a
--- /dev/null
@@ -0,0 +1,162 @@
+/* cfg80211 support
+ *
+ * See copyright notice in main.c
+ */
+#include <linux/ieee80211.h>
+#include <net/cfg80211.h>
+#include "hw.h"
+#include "main.h"
+#include "orinoco.h"
+
+#include "cfg.h"
+
+/* Supported bitrates. Must agree with hw.c */
+static struct ieee80211_rate orinoco_rates[] = {
+       { .bitrate = 10 },
+       { .bitrate = 20 },
+       { .bitrate = 55 },
+       { .bitrate = 110 },
+};
+
+static const void * const orinoco_wiphy_privid = &orinoco_wiphy_privid;
+
+/* Called after orinoco_private is allocated. */
+void orinoco_wiphy_init(struct wiphy *wiphy)
+{
+       struct orinoco_private *priv = wiphy_priv(wiphy);
+
+       wiphy->privid = orinoco_wiphy_privid;
+
+       set_wiphy_dev(wiphy, priv->dev);
+}
+
+/* Called after firmware is initialised */
+int orinoco_wiphy_register(struct wiphy *wiphy)
+{
+       struct orinoco_private *priv = wiphy_priv(wiphy);
+       int i, channels = 0;
+
+       if (priv->firmware_type == FIRMWARE_TYPE_AGERE)
+               wiphy->max_scan_ssids = 1;
+       else
+               wiphy->max_scan_ssids = 0;
+
+       wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
+
+       /* TODO: should we set if we only have demo ad-hoc?
+        *       (priv->has_port3)
+        */
+       if (priv->has_ibss)
+               wiphy->interface_modes |= BIT(NL80211_IFTYPE_ADHOC);
+
+       if (!priv->broken_monitor || force_monitor)
+               wiphy->interface_modes |= BIT(NL80211_IFTYPE_MONITOR);
+
+       priv->band.bitrates = orinoco_rates;
+       priv->band.n_bitrates = ARRAY_SIZE(orinoco_rates);
+
+       /* Only support channels allowed by the card EEPROM */
+       for (i = 0; i < NUM_CHANNELS; i++) {
+               if (priv->channel_mask & (1 << i)) {
+                       priv->channels[i].center_freq =
+                               ieee80211_dsss_chan_to_freq(i+1);
+                       channels++;
+               }
+       }
+       priv->band.channels = priv->channels;
+       priv->band.n_channels = channels;
+
+       wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->band;
+       wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
+
+       i = 0;
+       if (priv->has_wep) {
+               priv->cipher_suites[i] = WLAN_CIPHER_SUITE_WEP40;
+               i++;
+
+               if (priv->has_big_wep) {
+                       priv->cipher_suites[i] = WLAN_CIPHER_SUITE_WEP104;
+                       i++;
+               }
+       }
+       if (priv->has_wpa) {
+               priv->cipher_suites[i] = WLAN_CIPHER_SUITE_TKIP;
+               i++;
+       }
+       wiphy->cipher_suites = priv->cipher_suites;
+       wiphy->n_cipher_suites = i;
+
+       wiphy->rts_threshold = priv->rts_thresh;
+       if (!priv->has_mwo)
+               wiphy->frag_threshold = priv->frag_thresh;
+
+       return wiphy_register(wiphy);
+}
+
+static int orinoco_change_vif(struct wiphy *wiphy, struct net_device *dev,
+                             enum nl80211_iftype type, u32 *flags,
+                             struct vif_params *params)
+{
+       struct orinoco_private *priv = wiphy_priv(wiphy);
+       int err = 0;
+       unsigned long lock;
+
+       if (orinoco_lock(priv, &lock) != 0)
+               return -EBUSY;
+
+       switch (type) {
+       case NL80211_IFTYPE_ADHOC:
+               if (!priv->has_ibss && !priv->has_port3)
+                       err = -EINVAL;
+               break;
+
+       case NL80211_IFTYPE_STATION:
+               break;
+
+       case NL80211_IFTYPE_MONITOR:
+               if (priv->broken_monitor && !force_monitor) {
+                       printk(KERN_WARNING "%s: Monitor mode support is "
+                              "buggy in this firmware, not enabling\n",
+                              wiphy_name(wiphy));
+                       err = -EINVAL;
+               }
+               break;
+
+       default:
+               err = -EINVAL;
+       }
+
+       if (!err) {
+               priv->iw_mode = type;
+               set_port_type(priv);
+               err = orinoco_commit(priv);
+       }
+
+       orinoco_unlock(priv, &lock);
+
+       return err;
+}
+
+static int orinoco_scan(struct wiphy *wiphy, struct net_device *dev,
+                       struct cfg80211_scan_request *request)
+{
+       struct orinoco_private *priv = wiphy_priv(wiphy);
+       int err;
+
+       if (!request)
+               return -EINVAL;
+
+       if (priv->scan_request && priv->scan_request != request)
+               return -EBUSY;
+
+       priv->scan_request = request;
+
+       err = orinoco_hw_trigger_scan(priv, request->ssids);
+
+       return err;
+}
+
+const struct cfg80211_ops orinoco_cfg_ops = {
+       .change_virtual_intf = orinoco_change_vif,
+       .scan = orinoco_scan,
+};
diff --git a/drivers/net/wireless/orinoco/cfg.h b/drivers/net/wireless/orinoco/cfg.h
new file mode 100644 (file)
index 0000000..3ddc96a
--- /dev/null
@@ -0,0 +1,15 @@
+/* cfg80211 support.
+ *
+ * See copyright notice in main.c
+ */
+#ifndef ORINOCO_CFG_H
+#define ORINOCO_CFG_H
+
+#include <net/cfg80211.h>
+
+extern const struct cfg80211_ops orinoco_cfg_ops;
+
+void orinoco_wiphy_init(struct wiphy *wiphy);
+int orinoco_wiphy_register(struct wiphy *wiphy);
+
+#endif /* ORINOCO_CFG_H */
index 1084b43..1257250 100644 (file)
@@ -4,6 +4,7 @@
  */
 #include <linux/kernel.h>
 #include <linux/firmware.h>
+#include <linux/device.h>
 
 #include "hermes.h"
 #include "hermes_dld.h"
@@ -99,7 +100,7 @@ orinoco_dl_firmware(struct orinoco_private *priv,
        const void *end;
        const char *firmware;
        const char *fw_err;
-       struct net_device *dev = priv->ndev;
+       struct device *dev = priv->dev;
        int err = 0;
 
        pda = kzalloc(fw->pda_size, GFP_KERNEL);
@@ -111,12 +112,11 @@ orinoco_dl_firmware(struct orinoco_private *priv,
        else
                firmware = fw->sta_fw;
 
-       printk(KERN_DEBUG "%s: Attempting to download firmware %s\n",
-              dev->name, firmware);
+       dev_dbg(dev, "Attempting to download firmware %s\n", firmware);
 
        /* Read current plug data */
        err = hermes_read_pda(hw, pda, fw->pda_addr, fw->pda_size, 0);
-       printk(KERN_DEBUG "%s: Read PDA returned %d\n", dev->name, err);
+       dev_dbg(dev, "Read PDA returned %d\n", err);
        if (err)
                goto free;
 
@@ -124,8 +124,7 @@ orinoco_dl_firmware(struct orinoco_private *priv,
                err = request_firmware(&fw_entry, firmware, priv->dev);
 
                if (err) {
-                       printk(KERN_ERR "%s: Cannot find firmware %s\n",
-                              dev->name, firmware);
+                       dev_err(dev, "Cannot find firmware %s\n", firmware);
                        err = -ENOENT;
                        goto free;
                }
@@ -136,16 +135,15 @@ orinoco_dl_firmware(struct orinoco_private *priv,
 
        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);
+               dev_warn(dev, "Invalid firmware image detected (%s). "
+                        "Aborting download\n", 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);
+       dev_dbg(dev, "Program init returned %d\n", err);
        if (err != 0)
                goto abort;
 
@@ -156,7 +154,7 @@ orinoco_dl_firmware(struct orinoco_private *priv,
        end = fw_entry->data + fw_entry->size;
 
        err = hermes_program(hw, first_block, end);
-       printk(KERN_DEBUG "%s: Program returned %d\n", dev->name, err);
+       dev_dbg(dev, "Program returned %d\n", err);
        if (err != 0)
                goto abort;
 
@@ -167,19 +165,18 @@ orinoco_dl_firmware(struct orinoco_private *priv,
 
        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);
+       dev_dbg(dev, "Apply PDA returned %d\n", err);
        if (err)
                goto abort;
 
        /* Tell card we've finished */
        err = hermesi_program_end(hw);
-       printk(KERN_DEBUG "%s: Program end returned %d\n", dev->name, err);
+       dev_dbg(dev, "Program end returned %d\n", err);
        if (err != 0)
                goto abort;
 
        /* Check if we're running */
-       printk(KERN_DEBUG "%s: hermes_present returned %d\n",
-              dev->name, hermes_present(hw));
+       dev_dbg(dev, "hermes_present returned %d\n", hermes_present(hw));
 
 abort:
        /* If we requested the firmware, release it. */
@@ -282,14 +279,13 @@ static int
 symbol_dl_firmware(struct orinoco_private *priv,
                   const struct fw_info *fw)
 {
-       struct net_device *dev = priv->ndev;
+       struct device *dev = priv->dev;
        int ret;
        const struct firmware *fw_entry;
 
        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);
+                       dev_err(dev, "Cannot find firmware: %s\n", fw->pri_fw);
                        return -ENOENT;
                }
        } else
@@ -302,15 +298,13 @@ symbol_dl_firmware(struct orinoco_private *priv,
        if (!orinoco_cached_fw_get(priv, true))
                release_firmware(fw_entry);
        if (ret) {
-               printk(KERN_ERR "%s: Primary firmware download failed\n",
-                      dev->name);
+               dev_err(dev, "Primary firmware download failed\n");
                return ret;
        }
 
        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);
+                       dev_err(dev, "Cannot find firmware: %s\n", fw->sta_fw);
                        return -ENOENT;
                }
        } else
@@ -322,8 +316,7 @@ symbol_dl_firmware(struct orinoco_private *priv,
        if (!orinoco_cached_fw_get(priv, false))
                release_firmware(fw_entry);
        if (ret) {
-               printk(KERN_ERR "%s: Secondary firmware download failed\n",
-                      dev->name);
+               dev_err(dev, "Secondary firmware download failed\n");
        }
 
        return ret;
index f2c918c..1a2fca7 100644 (file)
@@ -469,7 +469,7 @@ int hermes_read_ltv(hermes_t *hw, int bap, u16 rid, unsigned bufsize,
        u16 rlength, rtype;
        unsigned nwords;
 
-       if ((bufsize < 0) || (bufsize % 2))
+       if (bufsize % 2)
                return -EINVAL;
 
        err = hermes_docmd_wait(hw, HERMES_CMD_ACCESS, rid, NULL);
index c78c442..2dddbb5 100644 (file)
@@ -342,7 +342,7 @@ struct agere_ext_scan_info {
        __le64  timestamp;
        __le16  beacon_interval;
        __le16  capabilities;
-       u8      data[316];
+       u8      data[0];
 } __attribute__ ((packed));
 
 #define HERMES_LINKSTATUS_NOT_CONNECTED   (0x0000)
index a9ba195..a3eefe1 100644 (file)
@@ -309,7 +309,7 @@ int hermes_read_pda(hermes_t *hw,
 
        /* Open auxiliary port */
        ret = hermes_aux_control(hw, 1);
-       printk(KERN_DEBUG PFX "AUX enable returned %d\n", ret);
+       pr_debug(PFX "AUX enable returned %d\n", ret);
        if (ret)
                return ret;
 
@@ -319,12 +319,12 @@ int hermes_read_pda(hermes_t *hw,
 
        /* Close aux port */
        ret = hermes_aux_control(hw, 0);
-       printk(KERN_DEBUG PFX "AUX disable returned %d\n", ret);
+       pr_debug(PFX "AUX disable returned %d\n", ret);
 
        /* Check PDA length */
        pda_size = le16_to_cpu(pda[0]);
-       printk(KERN_DEBUG PFX "Actual PDA length %d, Max allowed %d\n",
-              pda_size, pda_len);
+       pr_debug(PFX "Actual PDA length %d, Max allowed %d\n",
+                pda_size, pda_len);
        if (pda_size > pda_len)
                return -EINVAL;
 
@@ -422,20 +422,19 @@ int hermesi_program_init(hermes_t *hw, u32 offset)
                return err;
 
        err = hermes_aux_control(hw, 1);
-       printk(KERN_DEBUG PFX "AUX enable returned %d\n", err);
+       pr_debug(PFX "AUX enable returned %d\n", err);
 
        if (err)
                return err;
 
-       printk(KERN_DEBUG PFX "Enabling volatile, EP 0x%08x\n", offset);
+       pr_debug(KERN_DEBUG PFX "Enabling volatile, EP 0x%08x\n", offset);
        err = hermes_doicmd_wait(hw,
                                 HERMES_PROGRAM_ENABLE_VOLATILE,
                                 offset & 0xFFFFu,
                                 offset >> 16,
                                 0,
                                 NULL);
-       printk(KERN_DEBUG PFX "PROGRAM_ENABLE returned %d\n",
-              err);
+       pr_debug(PFX "PROGRAM_ENABLE returned %d\n", err);
 
        return err;
 }
@@ -454,16 +453,16 @@ int hermesi_program_end(hermes_t *hw)
 
        rc = hermes_docmd_wait(hw, HERMES_PROGRAM_DISABLE, 0, &resp);
 
-       printk(KERN_DEBUG PFX "PROGRAM_DISABLE returned %d, "
-              "r0 0x%04x, r1 0x%04x, r2 0x%04x\n",
-              rc, resp.resp0, resp.resp1, resp.resp2);
+       pr_debug(PFX "PROGRAM_DISABLE returned %d, "
+                "r0 0x%04x, r1 0x%04x, r2 0x%04x\n",
+                rc, resp.resp0, resp.resp1, resp.resp2);
 
        if ((rc == 0) &&
            ((resp.status & HERMES_STATUS_CMDCODE) != HERMES_CMD_DOWNLD))
                rc = -EIO;
 
        err = hermes_aux_control(hw, 0);
-       printk(KERN_DEBUG PFX "AUX disable returned %d\n", err);
+       pr_debug(PFX "AUX disable returned %d\n", err);
 
        /* Acknowledge any outstanding command */
        hermes_write_regn(hw, EVACK, 0xFFFF);
@@ -496,9 +495,8 @@ int hermes_program(hermes_t *hw, const char *first_block, const void *end)
 
        while ((blkaddr != BLOCK_END) &&
               (((void *) blk + blklen) <= end)) {
-               printk(KERN_DEBUG PFX
-                      "Programming block of length %d to address 0x%08x\n",
-                      blklen, blkaddr);
+               pr_debug(PFX "Programming block of length %d "
+                        "to address 0x%08x\n", blklen, blkaddr);
 
 #if !LIMIT_PROGRAM_SIZE
                /* wl_lkm driver splits this into writes of 2000 bytes */
@@ -510,10 +508,9 @@ int hermes_program(hermes_t *hw, const char *first_block, const void *end)
                addr = blkaddr;
 
                while (addr < (blkaddr + blklen)) {
-                       printk(KERN_DEBUG PFX
-                              "Programming subblock of length %d "
-                              "to address 0x%08x. Data @ %p\n",
-                              len, addr, &blk->data[addr - blkaddr]);
+                       pr_debug(PFX "Programming subblock of length %d "
+                                "to address 0x%08x. Data @ %p\n",
+                                len, addr, &blk->data[addr - blkaddr]);
 
                        hermes_aux_setaddr(hw, addr);
                        hermes_write_bytes(hw, HERMES_AUXDATA,
@@ -643,8 +640,8 @@ int hermes_apply_pda_with_defaults(hermes_t *hw,
 
                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);
+                       pr_debug(PFX "Found record 0x%04x at %p\n",
+                                record_id, pdi);
 
                switch (record_id) {
                case 0x110: /* Modem REFDAC values */
@@ -654,9 +651,9 @@ int hermes_apply_pda_with_defaults(hermes_t *hw,
                        default_pdi = NULL;
                        if (outdoor_pdi) {
                                pdi = outdoor_pdi;
-                               printk(KERN_DEBUG PFX
-                                      "Using outdoor record 0x%04x at %p\n",
-                                      record_id + 1, pdi);
+                               pr_debug(PFX
+                                        "Using outdoor record 0x%04x at %p\n",
+                                        record_id + 1, pdi);
                        }
                        break;
                case 0x5: /*  HWIF Compatiblity */
@@ -684,9 +681,8 @@ int hermes_apply_pda_with_defaults(hermes_t *hw,
                if (!pdi && default_pdi) {
                        /* Use default */
                        pdi = default_pdi;
-                       printk(KERN_DEBUG PFX
-                              "Using default record 0x%04x at %p\n",
-                              record_id, pdi);
+                       pr_debug(PFX "Using default record 0x%04x at %p\n",
+                                record_id, pdi);
                }
 
                if (pdi) {
index 632fac8..fa508af 100644 (file)
@@ -3,16 +3,22 @@
  * See copyright notice in main.c
  */
 #include <linux/kernel.h>
+#include <linux/device.h>
 #include <linux/if_arp.h>
 #include <linux/ieee80211.h>
 #include <linux/wireless.h>
-
+#include <net/cfg80211.h>
 #include "hermes.h"
 #include "hermes_rid.h"
 #include "orinoco.h"
 
 #include "hw.h"
 
+#define SYMBOL_MAX_VER_LEN     (14)
+
+/* Symbol firmware has a bug allocating buffers larger than this */
+#define TX_NICBUF_SIZE_BUG     1585
+
 /********************************************************************/
 /* Data tables                                                      */
 /********************************************************************/
@@ -36,6 +42,343 @@ static const struct {
 };
 #define BITRATE_TABLE_SIZE ARRAY_SIZE(bitrate_table)
 
+/* Firmware version encoding */
+struct comp_id {
+       u16 id, variant, major, minor;
+} __attribute__ ((packed));
+
+static inline fwtype_t determine_firmware_type(struct comp_id *nic_id)
+{
+       if (nic_id->id < 0x8000)
+               return FIRMWARE_TYPE_AGERE;
+       else if (nic_id->id == 0x8000 && nic_id->major == 0)
+               return FIRMWARE_TYPE_SYMBOL;
+       else
+               return FIRMWARE_TYPE_INTERSIL;
+}
+
+/* Set priv->firmware type, determine firmware properties
+ * This function can be called before we have registerred with netdev,
+ * so all errors go out with dev_* rather than printk
+ */
+int determine_fw_capabilities(struct orinoco_private *priv)
+{
+       struct device *dev = priv->dev;
+       hermes_t *hw = &priv->hw;
+       int err;
+       struct comp_id nic_id, sta_id;
+       unsigned int firmver;
+       char tmp[SYMBOL_MAX_VER_LEN+1] __attribute__((aligned(2)));
+
+       /* Get the hardware version */
+       err = HERMES_READ_RECORD(hw, USER_BAP, HERMES_RID_NICID, &nic_id);
+       if (err) {
+               dev_err(dev, "Cannot read hardware identity: error %d\n",
+                       err);
+               return err;
+       }
+
+       le16_to_cpus(&nic_id.id);
+       le16_to_cpus(&nic_id.variant);
+       le16_to_cpus(&nic_id.major);
+       le16_to_cpus(&nic_id.minor);
+       dev_info(dev, "Hardware identity %04x:%04x:%04x:%04x\n",
+                nic_id.id, nic_id.variant, nic_id.major, nic_id.minor);
+
+       priv->firmware_type = determine_firmware_type(&nic_id);
+
+       /* Get the firmware version */
+       err = HERMES_READ_RECORD(hw, USER_BAP, HERMES_RID_STAID, &sta_id);
+       if (err) {
+               dev_err(dev, "Cannot read station identity: error %d\n",
+                       err);
+               return err;
+       }
+
+       le16_to_cpus(&sta_id.id);
+       le16_to_cpus(&sta_id.variant);
+       le16_to_cpus(&sta_id.major);
+       le16_to_cpus(&sta_id.minor);
+       dev_info(dev, "Station identity  %04x:%04x:%04x:%04x\n",
+                sta_id.id, sta_id.variant, sta_id.major, sta_id.minor);
+
+       switch (sta_id.id) {
+       case 0x15:
+               dev_err(dev, "Primary firmware is active\n");
+               return -ENODEV;
+       case 0x14b:
+               dev_err(dev, "Tertiary firmware is active\n");
+               return -ENODEV;
+       case 0x1f:      /* Intersil, Agere, Symbol Spectrum24 */
+       case 0x21:      /* Symbol Spectrum24 Trilogy */
+               break;
+       default:
+               dev_notice(dev, "Unknown station ID, please report\n");
+               break;
+       }
+
+       /* Default capabilities */
+       priv->has_sensitivity = 1;
+       priv->has_mwo = 0;
+       priv->has_preamble = 0;
+       priv->has_port3 = 1;
+       priv->has_ibss = 1;
+       priv->has_wep = 0;
+       priv->has_big_wep = 0;
+       priv->has_alt_txcntl = 0;
+       priv->has_ext_scan = 0;
+       priv->has_wpa = 0;
+       priv->do_fw_download = 0;
+
+       /* Determine capabilities from the firmware version */
+       switch (priv->firmware_type) {
+       case FIRMWARE_TYPE_AGERE:
+               /* Lucent Wavelan IEEE, Lucent Orinoco, Cabletron RoamAbout,
+                  ELSA, Melco, HP, IBM, Dell 1150, Compaq 110/210 */
+               snprintf(priv->fw_name, sizeof(priv->fw_name) - 1,
+                        "Lucent/Agere %d.%02d", sta_id.major, sta_id.minor);
+
+               firmver = ((unsigned long)sta_id.major << 16) | sta_id.minor;
+
+               priv->has_ibss = (firmver >= 0x60006);
+               priv->has_wep = (firmver >= 0x40020);
+               priv->has_big_wep = 1; /* FIXME: this is wrong - how do we tell
+                                         Gold cards from the others? */
+               priv->has_mwo = (firmver >= 0x60000);
+               priv->has_pm = (firmver >= 0x40020); /* Don't work in 7.52 ? */
+               priv->ibss_port = 1;
+               priv->has_hostscan = (firmver >= 0x8000a);
+               priv->do_fw_download = 1;
+               priv->broken_monitor = (firmver >= 0x80000);
+               priv->has_alt_txcntl = (firmver >= 0x90000); /* All 9.x ? */
+               priv->has_ext_scan = (firmver >= 0x90000); /* All 9.x ? */
+               priv->has_wpa = (firmver >= 0x9002a);
+               /* Tested with Agere firmware :
+                *      1.16 ; 4.08 ; 4.52 ; 6.04 ; 6.16 ; 7.28 => Jean II
+                * Tested CableTron firmware : 4.32 => Anton */
+               break;
+       case FIRMWARE_TYPE_SYMBOL:
+               /* Symbol , 3Com AirConnect, Intel, Ericsson WLAN */
+               /* Intel MAC : 00:02:B3:* */
+               /* 3Com MAC : 00:50:DA:* */
+               memset(tmp, 0, sizeof(tmp));
+               /* Get the Symbol firmware version */
+               err = hermes_read_ltv(hw, USER_BAP,
+                                     HERMES_RID_SECONDARYVERSION_SYMBOL,
+                                     SYMBOL_MAX_VER_LEN, NULL, &tmp);
+               if (err) {
+                       dev_warn(dev, "Error %d reading Symbol firmware info. "
+                                "Wildly guessing capabilities...\n", err);
+                       firmver = 0;
+                       tmp[0] = '\0';
+               } else {
+                       /* The firmware revision is a string, the format is
+                        * something like : "V2.20-01".
+                        * Quick and dirty parsing... - Jean II
+                        */
+                       firmver = ((tmp[1] - '0') << 16)
+                               | ((tmp[3] - '0') << 12)
+                               | ((tmp[4] - '0') << 8)
+                               | ((tmp[6] - '0') << 4)
+                               | (tmp[7] - '0');
+
+                       tmp[SYMBOL_MAX_VER_LEN] = '\0';
+               }
+
+               snprintf(priv->fw_name, sizeof(priv->fw_name) - 1,
+                        "Symbol %s", tmp);
+
+               priv->has_ibss = (firmver >= 0x20000);
+               priv->has_wep = (firmver >= 0x15012);
+               priv->has_big_wep = (firmver >= 0x20000);
+               priv->has_pm = (firmver >= 0x20000 && firmver < 0x22000) ||
+                              (firmver >= 0x29000 && firmver < 0x30000) ||
+                              firmver >= 0x31000;
+               priv->has_preamble = (firmver >= 0x20000);
+               priv->ibss_port = 4;
+
+               /* Symbol firmware is found on various cards, but
+                * there has been no attempt to check firmware
+                * download on non-spectrum_cs based cards.
+                *
+                * Given that the Agere firmware download works
+                * differently, we should avoid doing a firmware
+                * download with the Symbol algorithm on non-spectrum
+                * cards.
+                *
+                * For now we can identify a spectrum_cs based card
+                * because it has a firmware reset function.
+                */
+               priv->do_fw_download = (priv->stop_fw != NULL);
+
+               priv->broken_disableport = (firmver == 0x25013) ||
+                               (firmver >= 0x30000 && firmver <= 0x31000);
+               priv->has_hostscan = (firmver >= 0x31001) ||
+                                    (firmver >= 0x29057 && firmver < 0x30000);
+               /* Tested with Intel firmware : 0x20015 => Jean II */
+               /* Tested with 3Com firmware : 0x15012 & 0x22001 => Jean II */
+               break;
+       case FIRMWARE_TYPE_INTERSIL:
+               /* D-Link, Linksys, Adtron, ZoomAir, and many others...
+                * Samsung, Compaq 100/200 and Proxim are slightly
+                * different and less well tested */
+               /* D-Link MAC : 00:40:05:* */
+               /* Addtron MAC : 00:90:D1:* */
+               snprintf(priv->fw_name, sizeof(priv->fw_name) - 1,
+                        "Intersil %d.%d.%d", sta_id.major, sta_id.minor,
+                        sta_id.variant);
+
+               firmver = ((unsigned long)sta_id.major << 16) |
+                       ((unsigned long)sta_id.minor << 8) | sta_id.variant;
+
+               priv->has_ibss = (firmver >= 0x000700); /* FIXME */
+               priv->has_big_wep = priv->has_wep = (firmver >= 0x000800);
+               priv->has_pm = (firmver >= 0x000700);
+               priv->has_hostscan = (firmver >= 0x010301);
+
+               if (firmver >= 0x000800)
+                       priv->ibss_port = 0;
+               else {
+                       dev_notice(dev, "Intersil firmware earlier than v0.8.x"
+                                  " - several features not supported\n");
+                       priv->ibss_port = 1;
+               }
+               break;
+       }
+       dev_info(dev, "Firmware determined as %s\n", priv->fw_name);
+
+       return 0;
+}
+
+/* Read settings from EEPROM into our private structure.
+ * MAC address gets dropped into callers buffer
+ * Can be called before netdev registration.
+ */
+int orinoco_hw_read_card_settings(struct orinoco_private *priv, u8 *dev_addr)
+{
+       struct device *dev = priv->dev;
+       struct hermes_idstring nickbuf;
+       hermes_t *hw = &priv->hw;
+       int len;
+       int err;
+       u16 reclen;
+
+       /* Get the MAC address */
+       err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNFOWNMACADDR,
+                             ETH_ALEN, NULL, dev_addr);
+       if (err) {
+               dev_warn(dev, "Failed to read MAC address!\n");
+               goto out;
+       }
+
+       dev_dbg(dev, "MAC address %pM\n", dev_addr);
+
+       /* Get the station name */
+       err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNFOWNNAME,
+                             sizeof(nickbuf), &reclen, &nickbuf);
+       if (err) {
+               dev_err(dev, "failed to read station name\n");
+               goto out;
+       }
+       if (nickbuf.len)
+               len = min(IW_ESSID_MAX_SIZE, (int)le16_to_cpu(nickbuf.len));
+       else
+               len = min(IW_ESSID_MAX_SIZE, 2 * reclen);
+       memcpy(priv->nick, &nickbuf.val, len);
+       priv->nick[len] = '\0';
+
+       dev_dbg(dev, "Station name \"%s\"\n", priv->nick);
+
+       /* Get allowed channels */
+       err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CHANNELLIST,
+                                 &priv->channel_mask);
+       if (err) {
+               dev_err(dev, "Failed to read channel list!\n");
+               goto out;
+       }
+
+       /* Get initial AP density */
+       err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFSYSTEMSCALE,
+                                 &priv->ap_density);
+       if (err || priv->ap_density < 1 || priv->ap_density > 3)
+               priv->has_sensitivity = 0;
+
+       /* Get initial RTS threshold */
+       err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFRTSTHRESHOLD,
+                                 &priv->rts_thresh);
+       if (err) {
+               dev_err(dev, "Failed to read RTS threshold!\n");
+               goto out;
+       }
+
+       /* Get initial fragmentation settings */
+       if (priv->has_mwo)
+               err = hermes_read_wordrec(hw, USER_BAP,
+                                         HERMES_RID_CNFMWOROBUST_AGERE,
+                                         &priv->mwo_robust);
+       else
+               err = hermes_read_wordrec(hw, USER_BAP,
+                                         HERMES_RID_CNFFRAGMENTATIONTHRESHOLD,
+                                         &priv->frag_thresh);
+       if (err) {
+               dev_err(dev, "Failed to read fragmentation settings!\n");
+               goto out;
+       }
+
+       /* Power management setup */
+       if (priv->has_pm) {
+               priv->pm_on = 0;
+               priv->pm_mcast = 1;
+               err = hermes_read_wordrec(hw, USER_BAP,
+                                         HERMES_RID_CNFMAXSLEEPDURATION,
+                                         &priv->pm_period);
+               if (err) {
+                       dev_err(dev, "Failed to read power management "
+                               "period!\n");
+                       goto out;
+               }
+               err = hermes_read_wordrec(hw, USER_BAP,
+                                         HERMES_RID_CNFPMHOLDOVERDURATION,
+                                         &priv->pm_timeout);
+               if (err) {
+                       dev_err(dev, "Failed to read power management "
+                               "timeout!\n");
+                       goto out;
+               }
+       }
+
+       /* Preamble setup */
+       if (priv->has_preamble) {
+               err = hermes_read_wordrec(hw, USER_BAP,
+                                         HERMES_RID_CNFPREAMBLE_SYMBOL,
+                                         &priv->preamble);
+       }
+
+out:
+       return err;
+}
+
+/* Can be called before netdev registration */
+int orinoco_hw_allocate_fid(struct orinoco_private *priv)
+{
+       struct device *dev = priv->dev;
+       struct hermes *hw = &priv->hw;
+       int err;
+
+       err = hermes_allocate(hw, priv->nicbuf_size, &priv->txfid);
+       if (err == -EIO && priv->nicbuf_size > TX_NICBUF_SIZE_BUG) {
+               /* Try workaround for old Symbol firmware bug */
+               priv->nicbuf_size = TX_NICBUF_SIZE_BUG;
+               err = hermes_allocate(hw, priv->nicbuf_size, &priv->txfid);
+
+               dev_warn(dev, "Firmware ALLOC bug detected "
+                        "(old Symbol firmware?). Work around %s\n",
+                        err ? "failed!" : "ok.");
+       }
+
+       return err;
+}
+
 int orinoco_get_bitratemode(int bitrate, int automatic)
 {
        int ratemode = -1;
@@ -63,6 +406,237 @@ void orinoco_get_ratemode_cfg(int ratemode, int *bitrate, int *automatic)
        *automatic = bitrate_table[ratemode].automatic;
 }
 
+int orinoco_hw_program_rids(struct orinoco_private *priv)
+{
+       struct net_device *dev = priv->ndev;
+       struct wireless_dev *wdev = netdev_priv(dev);
+       hermes_t *hw = &priv->hw;
+       int err;
+       struct hermes_idstring idbuf;
+
+       /* Set the MAC address */
+       err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNMACADDR,
+                              HERMES_BYTES_TO_RECLEN(ETH_ALEN), dev->dev_addr);
+       if (err) {
+               printk(KERN_ERR "%s: Error %d setting MAC address\n",
+                      dev->name, err);
+               return err;
+       }
+
+       /* Set up the link mode */
+       err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFPORTTYPE,
+                                  priv->port_type);
+       if (err) {
+               printk(KERN_ERR "%s: Error %d setting port type\n",
+                      dev->name, err);
+               return err;
+       }
+       /* Set the channel/frequency */
+       if (priv->channel != 0 && priv->iw_mode != NL80211_IFTYPE_STATION) {
+               err = hermes_write_wordrec(hw, USER_BAP,
+                                          HERMES_RID_CNFOWNCHANNEL,
+                                          priv->channel);
+               if (err) {
+                       printk(KERN_ERR "%s: Error %d setting channel %d\n",
+                              dev->name, err, priv->channel);
+                       return err;
+               }
+       }
+
+       if (priv->has_ibss) {
+               u16 createibss;
+
+               if ((strlen(priv->desired_essid) == 0) && (priv->createibss)) {
+                       printk(KERN_WARNING "%s: This firmware requires an "
+                              "ESSID in IBSS-Ad-Hoc mode.\n", dev->name);
+                       /* With wvlan_cs, in this case, we would crash.
+                        * hopefully, this driver will behave better...
+                        * Jean II */
+                       createibss = 0;
+               } else {
+                       createibss = priv->createibss;
+               }
+
+               err = hermes_write_wordrec(hw, USER_BAP,
+                                          HERMES_RID_CNFCREATEIBSS,
+                                          createibss);
+               if (err) {
+                       printk(KERN_ERR "%s: Error %d setting CREATEIBSS\n",
+                              dev->name, err);
+                       return err;
+               }
+       }
+
+       /* Set the desired BSSID */
+       err = __orinoco_hw_set_wap(priv);
+       if (err) {
+               printk(KERN_ERR "%s: Error %d setting AP address\n",
+                      dev->name, err);
+               return err;
+       }
+
+       /* Set the desired ESSID */
+       idbuf.len = cpu_to_le16(strlen(priv->desired_essid));
+       memcpy(&idbuf.val, priv->desired_essid, sizeof(idbuf.val));
+       /* WinXP wants partner to configure OWNSSID even in IBSS mode. (jimc) */
+       err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNSSID,
+                       HERMES_BYTES_TO_RECLEN(strlen(priv->desired_essid)+2),
+                       &idbuf);
+       if (err) {
+               printk(KERN_ERR "%s: Error %d setting OWNSSID\n",
+                      dev->name, err);
+               return err;
+       }
+       err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFDESIREDSSID,
+                       HERMES_BYTES_TO_RECLEN(strlen(priv->desired_essid)+2),
+                       &idbuf);
+       if (err) {
+               printk(KERN_ERR "%s: Error %d setting DESIREDSSID\n",
+                      dev->name, err);
+               return err;
+       }
+
+       /* Set the station name */
+       idbuf.len = cpu_to_le16(strlen(priv->nick));
+       memcpy(&idbuf.val, priv->nick, sizeof(idbuf.val));
+       err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNNAME,
+                              HERMES_BYTES_TO_RECLEN(strlen(priv->nick)+2),
+                              &idbuf);
+       if (err) {
+               printk(KERN_ERR "%s: Error %d setting nickname\n",
+                      dev->name, err);
+               return err;
+       }
+
+       /* Set AP density */
+       if (priv->has_sensitivity) {
+               err = hermes_write_wordrec(hw, USER_BAP,
+                                          HERMES_RID_CNFSYSTEMSCALE,
+                                          priv->ap_density);
+               if (err) {
+                       printk(KERN_WARNING "%s: Error %d setting SYSTEMSCALE. "
+                              "Disabling sensitivity control\n",
+                              dev->name, err);
+
+                       priv->has_sensitivity = 0;
+               }
+       }
+
+       /* Set RTS threshold */
+       err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFRTSTHRESHOLD,
+                                  priv->rts_thresh);
+       if (err) {
+               printk(KERN_ERR "%s: Error %d setting RTS threshold\n",
+                      dev->name, err);
+               return err;
+       }
+
+       /* Set fragmentation threshold or MWO robustness */
+       if (priv->has_mwo)
+               err = hermes_write_wordrec(hw, USER_BAP,
+                                          HERMES_RID_CNFMWOROBUST_AGERE,
+                                          priv->mwo_robust);
+       else
+               err = hermes_write_wordrec(hw, USER_BAP,
+                                          HERMES_RID_CNFFRAGMENTATIONTHRESHOLD,
+                                          priv->frag_thresh);
+       if (err) {
+               printk(KERN_ERR "%s: Error %d setting fragmentation\n",
+                      dev->name, err);
+               return err;
+       }
+
+       /* Set bitrate */
+       err = __orinoco_hw_set_bitrate(priv);
+       if (err) {
+               printk(KERN_ERR "%s: Error %d setting bitrate\n",
+                      dev->name, err);
+               return err;
+       }
+
+       /* Set power management */
+       if (priv->has_pm) {
+               err = hermes_write_wordrec(hw, USER_BAP,
+                                          HERMES_RID_CNFPMENABLED,
+                                          priv->pm_on);
+               if (err) {
+                       printk(KERN_ERR "%s: Error %d setting up PM\n",
+                              dev->name, err);
+                       return err;
+               }
+
+               err = hermes_write_wordrec(hw, USER_BAP,
+                                          HERMES_RID_CNFMULTICASTRECEIVE,
+                                          priv->pm_mcast);
+               if (err) {
+                       printk(KERN_ERR "%s: Error %d setting up PM\n",
+                              dev->name, err);
+                       return err;
+               }
+               err = hermes_write_wordrec(hw, USER_BAP,
+                                          HERMES_RID_CNFMAXSLEEPDURATION,
+                                          priv->pm_period);
+               if (err) {
+                       printk(KERN_ERR "%s: Error %d setting up PM\n",
+                              dev->name, err);
+                       return err;
+               }
+               err = hermes_write_wordrec(hw, USER_BAP,
+                                          HERMES_RID_CNFPMHOLDOVERDURATION,
+                                          priv->pm_timeout);
+               if (err) {
+                       printk(KERN_ERR "%s: Error %d setting up PM\n",
+                              dev->name, err);
+                       return err;
+               }
+       }
+
+       /* Set preamble - only for Symbol so far... */
+       if (priv->has_preamble) {
+               err = hermes_write_wordrec(hw, USER_BAP,
+                                          HERMES_RID_CNFPREAMBLE_SYMBOL,
+                                          priv->preamble);
+               if (err) {
+                       printk(KERN_ERR "%s: Error %d setting preamble\n",
+                              dev->name, err);
+                       return err;
+               }
+       }
+
+       /* Set up encryption */
+       if (priv->has_wep || priv->has_wpa) {
+               err = __orinoco_hw_setup_enc(priv);
+               if (err) {
+                       printk(KERN_ERR "%s: Error %d activating encryption\n",
+                              dev->name, err);
+                       return err;
+               }
+       }
+
+       if (priv->iw_mode == NL80211_IFTYPE_MONITOR) {
+               /* Enable monitor mode */
+               dev->type = ARPHRD_IEEE80211;
+               err = hermes_docmd_wait(hw, HERMES_CMD_TEST |
+                                           HERMES_TEST_MONITOR, 0, NULL);
+       } else {
+               /* Disable monitor mode */
+               dev->type = ARPHRD_ETHER;
+               err = hermes_docmd_wait(hw, HERMES_CMD_TEST |
+                                           HERMES_TEST_STOP, 0, NULL);
+       }
+       if (err)
+               return err;
+
+       /* Reset promiscuity / multicast*/
+       priv->promiscuous = 0;
+       priv->mc_count = 0;
+
+       /* Record mode change */
+       wdev->iftype = priv->iw_mode;
+
+       return 0;
+}
+
 /* Get tsc from the firmware */
 int orinoco_hw_get_tkip_iv(struct orinoco_private *priv, int key, u8 *tsc)
 {
@@ -314,7 +888,7 @@ int __orinoco_hw_setup_enc(struct orinoco_private *priv)
                } else
                        master_wep_flag = 0;
 
-               if (priv->iw_mode == IW_MODE_MONITOR)
+               if (priv->iw_mode == NL80211_IFTYPE_MONITOR)
                        master_wep_flag |= HERMES_WEP_HOST_DECRYPT;
 
                /* Master WEP setting : on/off */
@@ -334,8 +908,8 @@ int __orinoco_hw_setup_enc(struct orinoco_private *priv)
  * rsc must be 8 bytes
  * tsc must be 8 bytes or NULL
  */
-int __orinoco_hw_set_tkip_key(hermes_t *hw, int key_idx, int set_tx,
-                             u8 *key, u8 *rsc, u8 *tsc)
+int __orinoco_hw_set_tkip_key(struct orinoco_private *priv, int key_idx,
+                             int set_tx, u8 *key, u8 *rsc, u8 *tsc)
 {
        struct {
                __le16 idx;
@@ -345,6 +919,7 @@ int __orinoco_hw_set_tkip_key(hermes_t *hw, int key_idx, int set_tx,
                u8 rx_mic[MIC_KEYLEN];
                u8 tsc[IW_ENCODE_SEQ_MAX_SIZE];
        } __attribute__ ((packed)) buf;
+       hermes_t *hw = &priv->hw;
        int ret;
        int err;
        int k;
@@ -582,3 +1157,88 @@ int orinoco_hw_get_bitratelist(struct orinoco_private *priv,
 
        return 0;
 }
+
+int orinoco_hw_trigger_scan(struct orinoco_private *priv,
+                           const struct cfg80211_ssid *ssid)
+{
+       struct net_device *dev = priv->ndev;
+       hermes_t *hw = &priv->hw;
+       unsigned long flags;
+       int err = 0;
+
+       if (orinoco_lock(priv, &flags) != 0)
+               return -EBUSY;
+
+       /* Scanning with port 0 disabled would fail */
+       if (!netif_running(dev)) {
+               err = -ENETDOWN;
+               goto out;
+       }
+
+       /* In monitor mode, the scan results are always empty.
+        * Probe responses are passed to the driver as received
+        * frames and could be processed in software. */
+       if (priv->iw_mode == NL80211_IFTYPE_MONITOR) {
+               err = -EOPNOTSUPP;
+               goto out;
+       }
+
+       if (priv->has_hostscan) {
+               switch (priv->firmware_type) {
+               case FIRMWARE_TYPE_SYMBOL:
+                       err = hermes_write_wordrec(hw, USER_BAP,
+                                               HERMES_RID_CNFHOSTSCAN_SYMBOL,
+                                               HERMES_HOSTSCAN_SYMBOL_ONCE |
+                                               HERMES_HOSTSCAN_SYMBOL_BCAST);
+                       break;
+               case FIRMWARE_TYPE_INTERSIL: {
+                       __le16 req[3];
+
+                       req[0] = cpu_to_le16(0x3fff);   /* All channels */
+                       req[1] = cpu_to_le16(0x0001);   /* rate 1 Mbps */
+                       req[2] = 0;                     /* Any ESSID */
+                       err = HERMES_WRITE_RECORD(hw, USER_BAP,
+                                                 HERMES_RID_CNFHOSTSCAN, &req);
+                       break;
+               }
+               case FIRMWARE_TYPE_AGERE:
+                       if (ssid->ssid_len > 0) {
+                               struct hermes_idstring idbuf;
+                               size_t len = ssid->ssid_len;
+
+                               idbuf.len = cpu_to_le16(len);
+                               memcpy(idbuf.val, ssid->ssid, len);
+
+                               err = hermes_write_ltv(hw, USER_BAP,
+                                              HERMES_RID_CNFSCANSSID_AGERE,
+                                              HERMES_BYTES_TO_RECLEN(len + 2),
+                                              &idbuf);
+                       } else
+                               err = hermes_write_wordrec(hw, USER_BAP,
+                                                  HERMES_RID_CNFSCANSSID_AGERE,
+                                                  0);  /* Any ESSID */
+                       if (err)
+                               break;
+
+                       if (priv->has_ext_scan) {
+                               err = hermes_write_wordrec(hw, USER_BAP,
+                                               HERMES_RID_CNFSCANCHANNELS2GHZ,
+                                               0x7FFF);
+                               if (err)
+                                       goto out;
+
+                               err = hermes_inquire(hw,
+                                                    HERMES_INQ_CHANNELINFO);
+                       } else
+                               err = hermes_inquire(hw, HERMES_INQ_SCAN);
+
+                       break;
+               }
+       } else
+               err = hermes_inquire(hw, HERMES_INQ_SCAN);
+
+ out:
+       orinoco_unlock(priv, &flags);
+
+       return err;
+}
index dc3f23a..27b4276 100644 (file)
@@ -7,6 +7,7 @@
 
 #include <linux/types.h>
 #include <linux/wireless.h>
+#include <net/cfg80211.h>
 
 /* Hardware BAPs */
 #define USER_BAP 0
 struct orinoco_private;
 struct dev_addr_list;
 
+int determine_fw_capabilities(struct orinoco_private *priv);
+int orinoco_hw_read_card_settings(struct orinoco_private *priv, u8 *dev_addr);
+int orinoco_hw_allocate_fid(struct orinoco_private *priv);
 int orinoco_get_bitratemode(int bitrate, int automatic);
 void orinoco_get_ratemode_cfg(int ratemode, int *bitrate, int *automatic);
 
+int orinoco_hw_program_rids(struct orinoco_private *priv);
 int orinoco_hw_get_tkip_iv(struct orinoco_private *priv, int key, u8 *tsc);
 int __orinoco_hw_set_bitrate(struct orinoco_private *priv);
 int orinoco_hw_get_act_bitrate(struct orinoco_private *priv, int *bitrate);
 int __orinoco_hw_set_wap(struct orinoco_private *priv);
 int __orinoco_hw_setup_wepkeys(struct orinoco_private *priv);
 int __orinoco_hw_setup_enc(struct orinoco_private *priv);
-int __orinoco_hw_set_tkip_key(hermes_t *hw, int key_idx, int set_tx,
-                             u8 *key, u8 *rsc, u8 *tsc);
+int __orinoco_hw_set_tkip_key(struct orinoco_private *priv, int key_idx,
+                             int set_tx, u8 *key, u8 *rsc, u8 *tsc);
 int orinoco_clear_tkip_key(struct orinoco_private *priv, int key_idx);
 int __orinoco_hw_set_multicast_list(struct orinoco_private *priv,
                                    struct dev_addr_list *mc_list,
@@ -43,5 +48,7 @@ int orinoco_hw_get_essid(struct orinoco_private *priv, int *active,
 int orinoco_hw_get_freq(struct orinoco_private *priv);
 int orinoco_hw_get_bitratelist(struct orinoco_private *priv,
                               int *numrates, s32 *rates, int max);
+int orinoco_hw_trigger_scan(struct orinoco_private *priv,
+                           const struct cfg80211_ssid *ssid);
 
 #endif /* _ORINOCO_HW_H_ */
index a370e51..e8c550a 100644 (file)
@@ -80,6 +80,7 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/delay.h>
+#include <linux/device.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/ethtool.h>
@@ -88,6 +89,7 @@
 #include <linux/wireless.h>
 #include <linux/ieee80211.h>
 #include <net/iw_handler.h>
+#include <net/cfg80211.h>
 
 #include "hermes_rid.h"
 #include "hermes_dld.h"
@@ -96,6 +98,7 @@
 #include "mic.h"
 #include "fw.h"
 #include "wext.h"
+#include "cfg.h"
 #include "main.h"
 
 #include "orinoco.h"
@@ -142,13 +145,11 @@ static const u8 encaps_hdr[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00};
 #define ORINOCO_MIN_MTU                256
 #define ORINOCO_MAX_MTU                (IEEE80211_MAX_DATA_LEN - ENCAPS_OVERHEAD)
 
-#define SYMBOL_MAX_VER_LEN     (14)
 #define MAX_IRQLOOPS_PER_IRQ   10
 #define MAX_IRQLOOPS_PER_JIFFY (20000/HZ) /* Based on a guestimate of
                                            * how many events the
                                            * device could
                                            * legitimately generate */
-#define TX_NICBUF_SIZE_BUG     1585            /* Bug in Symbol firmware */
 
 #define DUMMY_FID              0xFFFF
 
@@ -205,11 +206,21 @@ struct orinoco_rx_data {
        struct list_head list;
 };
 
+struct orinoco_scan_data {
+       void *buf;
+       size_t len;
+       int type;
+       struct list_head list;
+};
+
 /********************************************************************/
 /* Function prototypes                                              */
 /********************************************************************/
 
-static void __orinoco_set_multicast_list(struct net_device *dev);
+static int __orinoco_set_multicast_list(struct net_device *dev);
+static int __orinoco_up(struct orinoco_private *priv);
+static int __orinoco_down(struct orinoco_private *priv);
+static int __orinoco_commit(struct orinoco_private *priv);
 
 /********************************************************************/
 /* Internal helper functions                                        */
@@ -218,11 +229,11 @@ static void __orinoco_set_multicast_list(struct net_device *dev);
 void set_port_type(struct orinoco_private *priv)
 {
        switch (priv->iw_mode) {
-       case IW_MODE_INFRA:
+       case NL80211_IFTYPE_STATION:
                priv->port_type = 1;
                priv->createibss = 0;
                break;
-       case IW_MODE_ADHOC:
+       case NL80211_IFTYPE_ADHOC:
                if (priv->prefer_port3) {
                        priv->port_type = 3;
                        priv->createibss = 0;
@@ -231,7 +242,7 @@ void set_port_type(struct orinoco_private *priv)
                        priv->createibss = 1;
                }
                break;
-       case IW_MODE_MONITOR:
+       case NL80211_IFTYPE_MONITOR:
                priv->port_type = 3;
                priv->createibss = 0;
                break;
@@ -247,14 +258,14 @@ void set_port_type(struct orinoco_private *priv)
 
 static int orinoco_open(struct net_device *dev)
 {
-       struct orinoco_private *priv = netdev_priv(dev);
+       struct orinoco_private *priv = ndev_priv(dev);
        unsigned long flags;
        int err;
 
        if (orinoco_lock(priv, &flags) != 0)
                return -EBUSY;
 
-       err = __orinoco_up(dev);
+       err = __orinoco_up(priv);
 
        if (!err)
                priv->open = 1;
@@ -266,7 +277,7 @@ static int orinoco_open(struct net_device *dev)
 
 static int orinoco_stop(struct net_device *dev)
 {
-       struct orinoco_private *priv = netdev_priv(dev);
+       struct orinoco_private *priv = ndev_priv(dev);
        int err = 0;
 
        /* We mustn't use orinoco_lock() here, because we need to be
@@ -276,7 +287,7 @@ static int orinoco_stop(struct net_device *dev)
 
        priv->open = 0;
 
-       err = __orinoco_down(dev);
+       err = __orinoco_down(priv);
 
        spin_unlock_irq(&priv->lock);
 
@@ -285,14 +296,14 @@ static int orinoco_stop(struct net_device *dev)
 
 static struct net_device_stats *orinoco_get_stats(struct net_device *dev)
 {
-       struct orinoco_private *priv = netdev_priv(dev);
+       struct orinoco_private *priv = ndev_priv(dev);
 
        return &priv->stats;
 }
 
 static void orinoco_set_multicast_list(struct net_device *dev)
 {
-       struct orinoco_private *priv = netdev_priv(dev);
+       struct orinoco_private *priv = ndev_priv(dev);
        unsigned long flags;
 
        if (orinoco_lock(priv, &flags) != 0) {
@@ -307,7 +318,7 @@ static void orinoco_set_multicast_list(struct net_device *dev)
 
 static int orinoco_change_mtu(struct net_device *dev, int new_mtu)
 {
-       struct orinoco_private *priv = netdev_priv(dev);
+       struct orinoco_private *priv = ndev_priv(dev);
 
        if ((new_mtu < ORINOCO_MIN_MTU) || (new_mtu > ORINOCO_MAX_MTU))
                return -EINVAL;
@@ -328,7 +339,7 @@ static int orinoco_change_mtu(struct net_device *dev, int new_mtu)
 
 static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-       struct orinoco_private *priv = netdev_priv(dev);
+       struct orinoco_private *priv = ndev_priv(dev);
        struct net_device_stats *stats = &priv->stats;
        hermes_t *hw = &priv->hw;
        int err = 0;
@@ -355,7 +366,8 @@ static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
                return NETDEV_TX_BUSY;
        }
 
-       if (!netif_carrier_ok(dev) || (priv->iw_mode == IW_MODE_MONITOR)) {
+       if (!netif_carrier_ok(dev) ||
+           (priv->iw_mode == NL80211_IFTYPE_MONITOR)) {
                /* Oops, the firmware hasn't established a connection,
                   silently drop the packet (this seems to be the
                   safest approach). */
@@ -518,7 +530,7 @@ static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
 
 static void __orinoco_ev_alloc(struct net_device *dev, hermes_t *hw)
 {
-       struct orinoco_private *priv = netdev_priv(dev);
+       struct orinoco_private *priv = ndev_priv(dev);
        u16 fid = hermes_read_regn(hw, ALLOCFID);
 
        if (fid != priv->txfid) {
@@ -533,7 +545,7 @@ static void __orinoco_ev_alloc(struct net_device *dev, hermes_t *hw)
 
 static void __orinoco_ev_tx(struct net_device *dev, hermes_t *hw)
 {
-       struct orinoco_private *priv = netdev_priv(dev);
+       struct orinoco_private *priv = ndev_priv(dev);
        struct net_device_stats *stats = &priv->stats;
 
        stats->tx_packets++;
@@ -545,7 +557,7 @@ static void __orinoco_ev_tx(struct net_device *dev, hermes_t *hw)
 
 static void __orinoco_ev_txexc(struct net_device *dev, hermes_t *hw)
 {
-       struct orinoco_private *priv = netdev_priv(dev);
+       struct orinoco_private *priv = ndev_priv(dev);
        struct net_device_stats *stats = &priv->stats;
        u16 fid = hermes_read_regn(hw, TXCOMPLFID);
        u16 status;
@@ -601,7 +613,7 @@ static void __orinoco_ev_txexc(struct net_device *dev, hermes_t *hw)
 
 static void orinoco_tx_timeout(struct net_device *dev)
 {
-       struct orinoco_private *priv = netdev_priv(dev);
+       struct orinoco_private *priv = ndev_priv(dev);
        struct net_device_stats *stats = &priv->stats;
        struct hermes *hw = &priv->hw;
 
@@ -650,7 +662,7 @@ static void orinoco_stat_gather(struct net_device *dev,
                                struct sk_buff *skb,
                                struct hermes_rx_descriptor *desc)
 {
-       struct orinoco_private *priv = netdev_priv(dev);
+       struct orinoco_private *priv = ndev_priv(dev);
 
        /* Using spy support with lots of Rx packets, like in an
         * infrastructure (AP), will really slow down everything, because
@@ -687,7 +699,7 @@ static void orinoco_rx_monitor(struct net_device *dev, u16 rxfid,
        int err;
        int len;
        struct sk_buff *skb;
-       struct orinoco_private *priv = netdev_priv(dev);
+       struct orinoco_private *priv = ndev_priv(dev);
        struct net_device_stats *stats = &priv->stats;
        hermes_t *hw = &priv->hw;
 
@@ -778,7 +790,7 @@ static void orinoco_rx_monitor(struct net_device *dev, u16 rxfid,
 
 static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw)
 {
-       struct orinoco_private *priv = netdev_priv(dev);
+       struct orinoco_private *priv = ndev_priv(dev);
        struct net_device_stats *stats = &priv->stats;
        struct iw_statistics *wstats = &priv->wstats;
        struct sk_buff *skb = NULL;
@@ -816,7 +828,7 @@ static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw)
        }
 
        /* Handle frames in monitor mode */
-       if (priv->iw_mode == IW_MODE_MONITOR) {
+       if (priv->iw_mode == NL80211_IFTYPE_MONITOR) {
                orinoco_rx_monitor(dev, rxfid, desc);
                goto out;
        }
@@ -902,7 +914,7 @@ static void orinoco_rx(struct net_device *dev,
                       struct hermes_rx_descriptor *desc,
                       struct sk_buff *skb)
 {
-       struct orinoco_private *priv = netdev_priv(dev);
+       struct orinoco_private *priv = ndev_priv(dev);
        struct net_device_stats *stats = &priv->stats;
        u16 status, fc;
        int length;
@@ -1016,8 +1028,8 @@ static void orinoco_rx(struct net_device *dev,
 
 static void orinoco_rx_isr_tasklet(unsigned long data)
 {
-       struct net_device *dev = (struct net_device *) data;
-       struct orinoco_private *priv = netdev_priv(dev);
+       struct orinoco_private *priv = (struct orinoco_private *) data;
+       struct net_device *dev = priv->ndev;
        struct orinoco_rx_data *rx_data, *temp;
        struct hermes_rx_descriptor *desc;
        struct sk_buff *skb;
@@ -1260,9 +1272,81 @@ static void orinoco_send_wevents(struct work_struct *work)
        orinoco_unlock(priv, &flags);
 }
 
+static void qbuf_scan(struct orinoco_private *priv, void *buf,
+                     int len, int type)
+{
+       struct orinoco_scan_data *sd;
+       unsigned long flags;
+
+       sd = kmalloc(sizeof(*sd), GFP_ATOMIC);
+       sd->buf = buf;
+       sd->len = len;
+       sd->type = type;
+
+       spin_lock_irqsave(&priv->scan_lock, flags);
+       list_add_tail(&sd->list, &priv->scan_list);
+       spin_unlock_irqrestore(&priv->scan_lock, flags);
+
+       schedule_work(&priv->process_scan);
+}
+
+static void qabort_scan(struct orinoco_private *priv)
+{
+       struct orinoco_scan_data *sd;
+       unsigned long flags;
+
+       sd = kmalloc(sizeof(*sd), GFP_ATOMIC);
+       sd->len = -1; /* Abort */
+
+       spin_lock_irqsave(&priv->scan_lock, flags);
+       list_add_tail(&sd->list, &priv->scan_list);
+       spin_unlock_irqrestore(&priv->scan_lock, flags);
+
+       schedule_work(&priv->process_scan);
+}
+
+static void orinoco_process_scan_results(struct work_struct *work)
+{
+       struct orinoco_private *priv =
+               container_of(work, struct orinoco_private, process_scan);
+       struct orinoco_scan_data *sd, *temp;
+       unsigned long flags;
+       void *buf;
+       int len;
+       int type;
+
+       spin_lock_irqsave(&priv->scan_lock, flags);
+       list_for_each_entry_safe(sd, temp, &priv->scan_list, list) {
+               spin_unlock_irqrestore(&priv->scan_lock, flags);
+
+               buf = sd->buf;
+               len = sd->len;
+               type = sd->type;
+
+               list_del(&sd->list);
+               kfree(sd);
+
+               if (len > 0) {
+                       if (type == HERMES_INQ_CHANNELINFO)
+                               orinoco_add_extscan_result(priv, buf, len);
+                       else
+                               orinoco_add_hostscan_results(priv, buf, len);
+
+                       kfree(buf);
+               } else if (priv->scan_request) {
+                       /* Either abort or complete the scan */
+                       cfg80211_scan_done(priv->scan_request, (len < 0));
+                       priv->scan_request = NULL;
+               }
+
+               spin_lock_irqsave(&priv->scan_lock, flags);
+       }
+       spin_unlock_irqrestore(&priv->scan_lock, flags);
+}
+
 static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
 {
-       struct orinoco_private *priv = netdev_priv(dev);
+       struct orinoco_private *priv = ndev_priv(dev);
        u16 infofid;
        struct {
                __le16 len;
@@ -1327,7 +1411,7 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
                u16 newstatus;
                int connected;
 
-               if (priv->iw_mode == IW_MODE_MONITOR)
+               if (priv->iw_mode == NL80211_IFTYPE_MONITOR)
                        break;
 
                if (len != sizeof(linkstatus)) {
@@ -1346,7 +1430,7 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
                 * the hostscan frame can be requested.  */
                if (newstatus == HERMES_LINKSTATUS_AP_OUT_OF_RANGE &&
                    priv->firmware_type == FIRMWARE_TYPE_SYMBOL &&
-                   priv->has_hostscan && priv->scan_inprogress) {
+                   priv->has_hostscan && priv->scan_request) {
                        hermes_inquire(hw, HERMES_INQ_HOSTSCAN_SYMBOL);
                        break;
                }
@@ -1372,7 +1456,7 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
        }
        break;
        case HERMES_INQ_SCAN:
-               if (!priv->scan_inprogress && priv->bssid_fixed &&
+               if (!priv->scan_request && priv->bssid_fixed &&
                    priv->firmware_type == FIRMWARE_TYPE_INTERSIL) {
                        schedule_work(&priv->join_work);
                        break;
@@ -1382,30 +1466,30 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
        case HERMES_INQ_HOSTSCAN_SYMBOL: {
                /* Result of a scanning. Contains information about
                 * cells in the vicinity - Jean II */
-               union iwreq_data        wrqu;
                unsigned char *buf;
 
-               /* Scan is no longer in progress */
-               priv->scan_inprogress = 0;
-
                /* Sanity check */
                if (len > 4096) {
                        printk(KERN_WARNING "%s: Scan results too large (%d bytes)\n",
                               dev->name, len);
+                       qabort_scan(priv);
                        break;
                }
 
                /* Allocate buffer for results */
                buf = kmalloc(len, GFP_ATOMIC);
-               if (buf == NULL)
+               if (buf == NULL) {
                        /* No memory, so can't printk()... */
+                       qabort_scan(priv);
                        break;
+               }
 
                /* Read scan data */
                err = hermes_bap_pread(hw, IRQ_BAP, (void *) buf, len,
                                       infofid, sizeof(info));
                if (err) {
                        kfree(buf);
+                       qabort_scan(priv);
                        break;
                }
 
@@ -1419,24 +1503,14 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
                }
 #endif /* ORINOCO_DEBUG */
 
-               if (orinoco_process_scan_results(priv, buf, len) == 0) {
-                       /* Send an empty event to user space.
-                        * We don't send the received data on the event because
-                        * it would require us to do complex transcoding, and
-                        * we want to minimise the work done in the irq handler
-                        * Use a request to extract the data - Jean II */
-                       wrqu.data.length = 0;
-                       wrqu.data.flags = 0;
-                       wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL);
-               }
-               kfree(buf);
+               qbuf_scan(priv, buf, len, type);
        }
        break;
        case HERMES_INQ_CHANNELINFO:
        {
                struct agere_ext_scan_info *bss;
 
-               if (!priv->scan_inprogress) {
+               if (!priv->scan_request) {
                        printk(KERN_DEBUG "%s: Got chaninfo without scan, "
                               "len=%d\n", dev->name, len);
                        break;
@@ -1444,25 +1518,12 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
 
                /* An empty result indicates that the scan is complete */
                if (len == 0) {
-                       union iwreq_data        wrqu;
-
-                       /* Scan is no longer in progress */
-                       priv->scan_inprogress = 0;
-
-                       wrqu.data.length = 0;
-                       wrqu.data.flags = 0;
-                       wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL);
+                       qbuf_scan(priv, NULL, len, type);
                        break;
                }
 
                /* Sanity check */
-               else if (len > sizeof(*bss)) {
-                       printk(KERN_WARNING
-                              "%s: Ext scan results too large (%d bytes). "
-                              "Truncating results to %zd bytes.\n",
-                              dev->name, len, sizeof(*bss));
-                       len = sizeof(*bss);
-               } else if (len < (offsetof(struct agere_ext_scan_info,
+               else if (len < (offsetof(struct agere_ext_scan_info,
                                           data) + 2)) {
                        /* Drop this result now so we don't have to
                         * keep checking later */
@@ -1472,21 +1533,18 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
                        break;
                }
 
-               bss = kmalloc(sizeof(*bss), GFP_ATOMIC);
+               bss = kmalloc(len, GFP_ATOMIC);
                if (bss == NULL)
                        break;
 
                /* Read scan data */
                err = hermes_bap_pread(hw, IRQ_BAP, (void *) bss, len,
                                       infofid, sizeof(info));
-               if (err) {
+               if (err)
                        kfree(bss);
-                       break;
-               }
-
-               orinoco_add_ext_scan_result(priv, bss);
+               else
+                       qbuf_scan(priv, bss, len, type);
 
-               kfree(bss);
                break;
        }
        case HERMES_INQ_SEC_STAT_AGERE:
@@ -1501,6 +1559,8 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
                /* We don't actually do anything about it */
                break;
        }
+
+       return;
 }
 
 static void __orinoco_ev_infdrop(struct net_device *dev, hermes_t *hw)
@@ -1513,15 +1573,15 @@ static void __orinoco_ev_infdrop(struct net_device *dev, hermes_t *hw)
 /* Internal hardware control routines                               */
 /********************************************************************/
 
-int __orinoco_up(struct net_device *dev)
+static int __orinoco_up(struct orinoco_private *priv)
 {
-       struct orinoco_private *priv = netdev_priv(dev);
+       struct net_device *dev = priv->ndev;
        struct hermes *hw = &priv->hw;
        int err;
 
        netif_carrier_off(dev); /* just to make sure */
 
-       err = __orinoco_program_rids(dev);
+       err = __orinoco_commit(priv);
        if (err) {
                printk(KERN_ERR "%s: Error %d configuring card\n",
                       dev->name, err);
@@ -1541,11 +1601,10 @@ int __orinoco_up(struct net_device *dev)
 
        return 0;
 }
-EXPORT_SYMBOL(__orinoco_up);
 
-int __orinoco_down(struct net_device *dev)
+static int __orinoco_down(struct orinoco_private *priv)
 {
-       struct orinoco_private *priv = netdev_priv(dev);
+       struct net_device *dev = priv->ndev;
        struct hermes *hw = &priv->hw;
        int err;
 
@@ -1573,31 +1632,9 @@ int __orinoco_down(struct net_device *dev)
 
        return 0;
 }
-EXPORT_SYMBOL(__orinoco_down);
 
-static int orinoco_allocate_fid(struct net_device *dev)
+static int orinoco_reinit_firmware(struct orinoco_private *priv)
 {
-       struct orinoco_private *priv = netdev_priv(dev);
-       struct hermes *hw = &priv->hw;
-       int err;
-
-       err = hermes_allocate(hw, priv->nicbuf_size, &priv->txfid);
-       if (err == -EIO && priv->nicbuf_size > TX_NICBUF_SIZE_BUG) {
-               /* Try workaround for old Symbol firmware bug */
-               priv->nicbuf_size = TX_NICBUF_SIZE_BUG;
-               err = hermes_allocate(hw, priv->nicbuf_size, &priv->txfid);
-
-               printk(KERN_WARNING "%s: firmware ALLOC bug detected "
-                      "(old Symbol firmware?). Work around %s\n",
-                      dev->name, err ? "failed!" : "ok.");
-       }
-
-       return err;
-}
-
-int orinoco_reinit_firmware(struct net_device *dev)
-{
-       struct orinoco_private *priv = netdev_priv(dev);
        struct hermes *hw = &priv->hw;
        int err;
 
@@ -1608,246 +1645,15 @@ int orinoco_reinit_firmware(struct net_device *dev)
                        priv->do_fw_download = 0;
        }
        if (!err)
-               err = orinoco_allocate_fid(dev);
+               err = orinoco_hw_allocate_fid(priv);
 
        return err;
 }
-EXPORT_SYMBOL(orinoco_reinit_firmware);
-
-int __orinoco_program_rids(struct net_device *dev)
-{
-       struct orinoco_private *priv = netdev_priv(dev);
-       hermes_t *hw = &priv->hw;
-       int err;
-       struct hermes_idstring idbuf;
-
-       /* Set the MAC address */
-       err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNMACADDR,
-                              HERMES_BYTES_TO_RECLEN(ETH_ALEN), dev->dev_addr);
-       if (err) {
-               printk(KERN_ERR "%s: Error %d setting MAC address\n",
-                      dev->name, err);
-               return err;
-       }
-
-       /* Set up the link mode */
-       err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFPORTTYPE,
-                                  priv->port_type);
-       if (err) {
-               printk(KERN_ERR "%s: Error %d setting port type\n",
-                      dev->name, err);
-               return err;
-       }
-       /* Set the channel/frequency */
-       if (priv->channel != 0 && priv->iw_mode != IW_MODE_INFRA) {
-               err = hermes_write_wordrec(hw, USER_BAP,
-                                          HERMES_RID_CNFOWNCHANNEL,
-                                          priv->channel);
-               if (err) {
-                       printk(KERN_ERR "%s: Error %d setting channel %d\n",
-                              dev->name, err, priv->channel);
-                       return err;
-               }
-       }
-
-       if (priv->has_ibss) {
-               u16 createibss;
-
-               if ((strlen(priv->desired_essid) == 0) && (priv->createibss)) {
-                       printk(KERN_WARNING "%s: This firmware requires an "
-                              "ESSID in IBSS-Ad-Hoc mode.\n", dev->name);
-                       /* With wvlan_cs, in this case, we would crash.
-                        * hopefully, this driver will behave better...
-                        * Jean II */
-                       createibss = 0;
-               } else {
-                       createibss = priv->createibss;
-               }
-
-               err = hermes_write_wordrec(hw, USER_BAP,
-                                          HERMES_RID_CNFCREATEIBSS,
-                                          createibss);
-               if (err) {
-                       printk(KERN_ERR "%s: Error %d setting CREATEIBSS\n",
-                              dev->name, err);
-                       return err;
-               }
-       }
-
-       /* Set the desired BSSID */
-       err = __orinoco_hw_set_wap(priv);
-       if (err) {
-               printk(KERN_ERR "%s: Error %d setting AP address\n",
-                      dev->name, err);
-               return err;
-       }
-       /* Set the desired ESSID */
-       idbuf.len = cpu_to_le16(strlen(priv->desired_essid));
-       memcpy(&idbuf.val, priv->desired_essid, sizeof(idbuf.val));
-       /* WinXP wants partner to configure OWNSSID even in IBSS mode. (jimc) */
-       err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNSSID,
-                       HERMES_BYTES_TO_RECLEN(strlen(priv->desired_essid)+2),
-                       &idbuf);
-       if (err) {
-               printk(KERN_ERR "%s: Error %d setting OWNSSID\n",
-                      dev->name, err);
-               return err;
-       }
-       err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFDESIREDSSID,
-                       HERMES_BYTES_TO_RECLEN(strlen(priv->desired_essid)+2),
-                       &idbuf);
-       if (err) {
-               printk(KERN_ERR "%s: Error %d setting DESIREDSSID\n",
-                      dev->name, err);
-               return err;
-       }
-
-       /* Set the station name */
-       idbuf.len = cpu_to_le16(strlen(priv->nick));
-       memcpy(&idbuf.val, priv->nick, sizeof(idbuf.val));
-       err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNNAME,
-                              HERMES_BYTES_TO_RECLEN(strlen(priv->nick)+2),
-                              &idbuf);
-       if (err) {
-               printk(KERN_ERR "%s: Error %d setting nickname\n",
-                      dev->name, err);
-               return err;
-       }
-
-       /* Set AP density */
-       if (priv->has_sensitivity) {
-               err = hermes_write_wordrec(hw, USER_BAP,
-                                          HERMES_RID_CNFSYSTEMSCALE,
-                                          priv->ap_density);
-               if (err) {
-                       printk(KERN_WARNING "%s: Error %d setting SYSTEMSCALE. "
-                              "Disabling sensitivity control\n",
-                              dev->name, err);
-
-                       priv->has_sensitivity = 0;
-               }
-       }
-
-       /* Set RTS threshold */
-       err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFRTSTHRESHOLD,
-                                  priv->rts_thresh);
-       if (err) {
-               printk(KERN_ERR "%s: Error %d setting RTS threshold\n",
-                      dev->name, err);
-               return err;
-       }
-
-       /* Set fragmentation threshold or MWO robustness */
-       if (priv->has_mwo)
-               err = hermes_write_wordrec(hw, USER_BAP,
-                                          HERMES_RID_CNFMWOROBUST_AGERE,
-                                          priv->mwo_robust);
-       else
-               err = hermes_write_wordrec(hw, USER_BAP,
-                                          HERMES_RID_CNFFRAGMENTATIONTHRESHOLD,
-                                          priv->frag_thresh);
-       if (err) {
-               printk(KERN_ERR "%s: Error %d setting fragmentation\n",
-                      dev->name, err);
-               return err;
-       }
-
-       /* Set bitrate */
-       err = __orinoco_hw_set_bitrate(priv);
-       if (err) {
-               printk(KERN_ERR "%s: Error %d setting bitrate\n",
-                      dev->name, err);
-               return err;
-       }
-
-       /* Set power management */
-       if (priv->has_pm) {
-               err = hermes_write_wordrec(hw, USER_BAP,
-                                          HERMES_RID_CNFPMENABLED,
-                                          priv->pm_on);
-               if (err) {
-                       printk(KERN_ERR "%s: Error %d setting up PM\n",
-                              dev->name, err);
-                       return err;
-               }
-
-               err = hermes_write_wordrec(hw, USER_BAP,
-                                          HERMES_RID_CNFMULTICASTRECEIVE,
-                                          priv->pm_mcast);
-               if (err) {
-                       printk(KERN_ERR "%s: Error %d setting up PM\n",
-                              dev->name, err);
-                       return err;
-               }
-               err = hermes_write_wordrec(hw, USER_BAP,
-                                          HERMES_RID_CNFMAXSLEEPDURATION,
-                                          priv->pm_period);
-               if (err) {
-                       printk(KERN_ERR "%s: Error %d setting up PM\n",
-                              dev->name, err);
-                       return err;
-               }
-               err = hermes_write_wordrec(hw, USER_BAP,
-                                          HERMES_RID_CNFPMHOLDOVERDURATION,
-                                          priv->pm_timeout);
-               if (err) {
-                       printk(KERN_ERR "%s: Error %d setting up PM\n",
-                              dev->name, err);
-                       return err;
-               }
-       }
-
-       /* Set preamble - only for Symbol so far... */
-       if (priv->has_preamble) {
-               err = hermes_write_wordrec(hw, USER_BAP,
-                                          HERMES_RID_CNFPREAMBLE_SYMBOL,
-                                          priv->preamble);
-               if (err) {
-                       printk(KERN_ERR "%s: Error %d setting preamble\n",
-                              dev->name, err);
-                       return err;
-               }
-       }
-
-       /* Set up encryption */
-       if (priv->has_wep || priv->has_wpa) {
-               err = __orinoco_hw_setup_enc(priv);
-               if (err) {
-                       printk(KERN_ERR "%s: Error %d activating encryption\n",
-                              dev->name, err);
-                       return err;
-               }
-       }
-
-       if (priv->iw_mode == IW_MODE_MONITOR) {
-               /* Enable monitor mode */
-               dev->type = ARPHRD_IEEE80211;
-               err = hermes_docmd_wait(hw, HERMES_CMD_TEST |
-                                           HERMES_TEST_MONITOR, 0, NULL);
-       } else {
-               /* Disable monitor mode */
-               dev->type = ARPHRD_ETHER;
-               err = hermes_docmd_wait(hw, HERMES_CMD_TEST |
-                                           HERMES_TEST_STOP, 0, NULL);
-       }
-       if (err)
-               return err;
-
-       /* Set promiscuity / multicast*/
-       priv->promiscuous = 0;
-       priv->mc_count = 0;
-
-       /* FIXME: what about netif_tx_lock */
-       __orinoco_set_multicast_list(dev);
-
-       return 0;
-}
 
-/* FIXME: return int? */
-static void
+static int
 __orinoco_set_multicast_list(struct net_device *dev)
 {
-       struct orinoco_private *priv = netdev_priv(dev);
+       struct orinoco_private *priv = ndev_priv(dev);
        int err = 0;
        int promisc, mc_count;
 
@@ -1864,6 +1670,8 @@ __orinoco_set_multicast_list(struct net_device *dev)
 
        err = __orinoco_hw_set_multicast_list(priv, dev->mc_list, mc_count,
                                              promisc);
+
+       return err;
 }
 
 /* This must be called from user context, without locks held - use
@@ -1896,9 +1704,11 @@ void orinoco_reset(struct work_struct *work)
 
        orinoco_unlock(priv, &flags);
 
-       /* Scanning support: Cleanup of driver struct */
-       orinoco_clear_scan_results(priv, 0);
-       priv->scan_inprogress = 0;
+       /* Scanning support: Notify scan cancellation */
+       if (priv->scan_request) {
+               cfg80211_scan_done(priv->scan_request, 1);
+               priv->scan_request = NULL;
+       }
 
        if (priv->hard_reset) {
                err = (*priv->hard_reset)(priv);
@@ -1909,7 +1719,7 @@ void orinoco_reset(struct work_struct *work)
                }
        }
 
-       err = orinoco_reinit_firmware(dev);
+       err = orinoco_reinit_firmware(priv);
        if (err) {
                printk(KERN_ERR "%s: orinoco_reset: Error %d re-initializing firmware\n",
                       dev->name, err);
@@ -1924,7 +1734,7 @@ void orinoco_reset(struct work_struct *work)
        /* priv->open or priv->hw_unavailable might have changed while
         * we dropped the lock */
        if (priv->open && (!priv->hw_unavailable)) {
-               err = __orinoco_up(dev);
+               err = __orinoco_up(priv);
                if (err) {
                        printk(KERN_ERR "%s: orinoco_reset: Error %d reenabling card\n",
                               dev->name, err);
@@ -1941,6 +1751,64 @@ void orinoco_reset(struct work_struct *work)
        printk(KERN_ERR "%s: Device has been disabled!\n", dev->name);
 }
 
+static int __orinoco_commit(struct orinoco_private *priv)
+{
+       struct net_device *dev = priv->ndev;
+       int err = 0;
+
+       err = orinoco_hw_program_rids(priv);
+
+       /* FIXME: what about netif_tx_lock */
+       (void) __orinoco_set_multicast_list(dev);
+
+       return err;
+}
+
+/* Ensures configuration changes are applied. May result in a reset.
+ * The caller should hold priv->lock
+ */
+int orinoco_commit(struct orinoco_private *priv)
+{
+       struct net_device *dev = priv->ndev;
+       hermes_t *hw = &priv->hw;
+       int err;
+
+       if (priv->broken_disableport) {
+               schedule_work(&priv->reset_work);
+               return 0;
+       }
+
+       err = hermes_disable_port(hw, 0);
+       if (err) {
+               printk(KERN_WARNING "%s: Unable to disable port "
+                      "while reconfiguring card\n", dev->name);
+               priv->broken_disableport = 1;
+               goto out;
+       }
+
+       err = __orinoco_commit(priv);
+       if (err) {
+               printk(KERN_WARNING "%s: Unable to reconfigure card\n",
+                      dev->name);
+               goto out;
+       }
+
+       err = hermes_enable_port(hw, 0);
+       if (err) {
+               printk(KERN_WARNING "%s: Unable to enable port while reconfiguring card\n",
+                      dev->name);
+               goto out;
+       }
+
+ out:
+       if (err) {
+               printk(KERN_WARNING "%s: Resetting instead...\n", dev->name);
+               schedule_work(&priv->reset_work);
+               err = 0;
+       }
+       return err;
+}
+
 /********************************************************************/
 /* Interrupt handler                                                */
 /********************************************************************/
@@ -1960,8 +1828,8 @@ static void __orinoco_ev_wterr(struct net_device *dev, hermes_t *hw)
 
 irqreturn_t orinoco_interrupt(int irq, void *dev_id)
 {
-       struct net_device *dev = dev_id;
-       struct orinoco_private *priv = netdev_priv(dev);
+       struct orinoco_private *priv = dev_id;
+       struct net_device *dev = priv->ndev;
        hermes_t *hw = &priv->hw;
        int count = MAX_IRQLOOPS_PER_IRQ;
        u16 evstat, events;
@@ -2096,227 +1964,12 @@ static void orinoco_unregister_pm_notifier(struct orinoco_private *priv)
 /* Initialization                                                   */
 /********************************************************************/
 
-struct comp_id {
-       u16 id, variant, major, minor;
-} __attribute__ ((packed));
-
-static inline fwtype_t determine_firmware_type(struct comp_id *nic_id)
-{
-       if (nic_id->id < 0x8000)
-               return FIRMWARE_TYPE_AGERE;
-       else if (nic_id->id == 0x8000 && nic_id->major == 0)
-               return FIRMWARE_TYPE_SYMBOL;
-       else
-               return FIRMWARE_TYPE_INTERSIL;
-}
-
-/* Set priv->firmware type, determine firmware properties */
-static int determine_firmware(struct net_device *dev)
-{
-       struct orinoco_private *priv = netdev_priv(dev);
-       hermes_t *hw = &priv->hw;
-       int err;
-       struct comp_id nic_id, sta_id;
-       unsigned int firmver;
-       char tmp[SYMBOL_MAX_VER_LEN+1] __attribute__((aligned(2)));
-
-       /* Get the hardware version */
-       err = HERMES_READ_RECORD(hw, USER_BAP, HERMES_RID_NICID, &nic_id);
-       if (err) {
-               printk(KERN_ERR "%s: Cannot read hardware identity: error %d\n",
-                      dev->name, err);
-               return err;
-       }
-
-       le16_to_cpus(&nic_id.id);
-       le16_to_cpus(&nic_id.variant);
-       le16_to_cpus(&nic_id.major);
-       le16_to_cpus(&nic_id.minor);
-       printk(KERN_DEBUG "%s: Hardware identity %04x:%04x:%04x:%04x\n",
-              dev->name, nic_id.id, nic_id.variant,
-              nic_id.major, nic_id.minor);
-
-       priv->firmware_type = determine_firmware_type(&nic_id);
-
-       /* Get the firmware version */
-       err = HERMES_READ_RECORD(hw, USER_BAP, HERMES_RID_STAID, &sta_id);
-       if (err) {
-               printk(KERN_ERR "%s: Cannot read station identity: error %d\n",
-                      dev->name, err);
-               return err;
-       }
-
-       le16_to_cpus(&sta_id.id);
-       le16_to_cpus(&sta_id.variant);
-       le16_to_cpus(&sta_id.major);
-       le16_to_cpus(&sta_id.minor);
-       printk(KERN_DEBUG "%s: Station identity  %04x:%04x:%04x:%04x\n",
-              dev->name, sta_id.id, sta_id.variant,
-              sta_id.major, sta_id.minor);
-
-       switch (sta_id.id) {
-       case 0x15:
-               printk(KERN_ERR "%s: Primary firmware is active\n",
-                      dev->name);
-               return -ENODEV;
-       case 0x14b:
-               printk(KERN_ERR "%s: Tertiary firmware is active\n",
-                      dev->name);
-               return -ENODEV;
-       case 0x1f:      /* Intersil, Agere, Symbol Spectrum24 */
-       case 0x21:      /* Symbol Spectrum24 Trilogy */
-               break;
-       default:
-               printk(KERN_NOTICE "%s: Unknown station ID, please report\n",
-                      dev->name);
-               break;
-       }
-
-       /* Default capabilities */
-       priv->has_sensitivity = 1;
-       priv->has_mwo = 0;
-       priv->has_preamble = 0;
-       priv->has_port3 = 1;
-       priv->has_ibss = 1;
-       priv->has_wep = 0;
-       priv->has_big_wep = 0;
-       priv->has_alt_txcntl = 0;
-       priv->has_ext_scan = 0;
-       priv->has_wpa = 0;
-       priv->do_fw_download = 0;
-
-       /* Determine capabilities from the firmware version */
-       switch (priv->firmware_type) {
-       case FIRMWARE_TYPE_AGERE:
-               /* Lucent Wavelan IEEE, Lucent Orinoco, Cabletron RoamAbout,
-                  ELSA, Melco, HP, IBM, Dell 1150, Compaq 110/210 */
-               snprintf(priv->fw_name, sizeof(priv->fw_name) - 1,
-                        "Lucent/Agere %d.%02d", sta_id.major, sta_id.minor);
-
-               firmver = ((unsigned long)sta_id.major << 16) | sta_id.minor;
-
-               priv->has_ibss = (firmver >= 0x60006);
-               priv->has_wep = (firmver >= 0x40020);
-               priv->has_big_wep = 1; /* FIXME: this is wrong - how do we tell
-                                         Gold cards from the others? */
-               priv->has_mwo = (firmver >= 0x60000);
-               priv->has_pm = (firmver >= 0x40020); /* Don't work in 7.52 ? */
-               priv->ibss_port = 1;
-               priv->has_hostscan = (firmver >= 0x8000a);
-               priv->do_fw_download = 1;
-               priv->broken_monitor = (firmver >= 0x80000);
-               priv->has_alt_txcntl = (firmver >= 0x90000); /* All 9.x ? */
-               priv->has_ext_scan = (firmver >= 0x90000); /* All 9.x ? */
-               priv->has_wpa = (firmver >= 0x9002a);
-               /* Tested with Agere firmware :
-                *      1.16 ; 4.08 ; 4.52 ; 6.04 ; 6.16 ; 7.28 => Jean II
-                * Tested CableTron firmware : 4.32 => Anton */
-               break;
-       case FIRMWARE_TYPE_SYMBOL:
-               /* Symbol , 3Com AirConnect, Intel, Ericsson WLAN */
-               /* Intel MAC : 00:02:B3:* */
-               /* 3Com MAC : 00:50:DA:* */
-               memset(tmp, 0, sizeof(tmp));
-               /* Get the Symbol firmware version */
-               err = hermes_read_ltv(hw, USER_BAP,
-                                     HERMES_RID_SECONDARYVERSION_SYMBOL,
-                                     SYMBOL_MAX_VER_LEN, NULL, &tmp);
-               if (err) {
-                       printk(KERN_WARNING
-                              "%s: Error %d reading Symbol firmware info. "
-                              "Wildly guessing capabilities...\n",
-                              dev->name, err);
-                       firmver = 0;
-                       tmp[0] = '\0';
-               } else {
-                       /* The firmware revision is a string, the format is
-                        * something like : "V2.20-01".
-                        * Quick and dirty parsing... - Jean II
-                        */
-                       firmver = ((tmp[1] - '0') << 16)
-                               | ((tmp[3] - '0') << 12)
-                               | ((tmp[4] - '0') << 8)
-                               | ((tmp[6] - '0') << 4)
-                               | (tmp[7] - '0');
-
-                       tmp[SYMBOL_MAX_VER_LEN] = '\0';
-               }
-
-               snprintf(priv->fw_name, sizeof(priv->fw_name) - 1,
-                        "Symbol %s", tmp);
-
-               priv->has_ibss = (firmver >= 0x20000);
-               priv->has_wep = (firmver >= 0x15012);
-               priv->has_big_wep = (firmver >= 0x20000);
-               priv->has_pm = (firmver >= 0x20000 && firmver < 0x22000) ||
-                              (firmver >= 0x29000 && firmver < 0x30000) ||
-                              firmver >= 0x31000;
-               priv->has_preamble = (firmver >= 0x20000);
-               priv->ibss_port = 4;
-
-               /* Symbol firmware is found on various cards, but
-                * there has been no attempt to check firmware
-                * download on non-spectrum_cs based cards.
-                *
-                * Given that the Agere firmware download works
-                * differently, we should avoid doing a firmware
-                * download with the Symbol algorithm on non-spectrum
-                * cards.
-                *
-                * For now we can identify a spectrum_cs based card
-                * because it has a firmware reset function.
-                */
-               priv->do_fw_download = (priv->stop_fw != NULL);
-
-               priv->broken_disableport = (firmver == 0x25013) ||
-                               (firmver >= 0x30000 && firmver <= 0x31000);
-               priv->has_hostscan = (firmver >= 0x31001) ||
-                                    (firmver >= 0x29057 && firmver < 0x30000);
-               /* Tested with Intel firmware : 0x20015 => Jean II */
-               /* Tested with 3Com firmware : 0x15012 & 0x22001 => Jean II */
-               break;
-       case FIRMWARE_TYPE_INTERSIL:
-               /* D-Link, Linksys, Adtron, ZoomAir, and many others...
-                * Samsung, Compaq 100/200 and Proxim are slightly
-                * different and less well tested */
-               /* D-Link MAC : 00:40:05:* */
-               /* Addtron MAC : 00:90:D1:* */
-               snprintf(priv->fw_name, sizeof(priv->fw_name) - 1,
-                        "Intersil %d.%d.%d", sta_id.major, sta_id.minor,
-                        sta_id.variant);
-
-               firmver = ((unsigned long)sta_id.major << 16) |
-                       ((unsigned long)sta_id.minor << 8) | sta_id.variant;
-
-               priv->has_ibss = (firmver >= 0x000700); /* FIXME */
-               priv->has_big_wep = priv->has_wep = (firmver >= 0x000800);
-               priv->has_pm = (firmver >= 0x000700);
-               priv->has_hostscan = (firmver >= 0x010301);
-
-               if (firmver >= 0x000800)
-                       priv->ibss_port = 0;
-               else {
-                       printk(KERN_NOTICE "%s: Intersil firmware earlier "
-                              "than v0.8.x - several features not supported\n",
-                              dev->name);
-                       priv->ibss_port = 1;
-               }
-               break;
-       }
-       printk(KERN_DEBUG "%s: Firmware determined as %s\n", dev->name,
-              priv->fw_name);
-
-       return 0;
-}
-
-static int orinoco_init(struct net_device *dev)
+int orinoco_init(struct orinoco_private *priv)
 {
-       struct orinoco_private *priv = netdev_priv(dev);
+       struct device *dev = priv->dev;
+       struct wiphy *wiphy = priv_to_wiphy(priv);
        hermes_t *hw = &priv->hw;
        int err = 0;
-       struct hermes_idstring nickbuf;
-       u16 reclen;
-       int len;
 
        /* No need to lock, the hw_unavailable flag is already set in
         * alloc_orinocodev() */
@@ -2325,15 +1978,14 @@ static int orinoco_init(struct net_device *dev)
        /* Initialize the firmware */
        err = hermes_init(hw);
        if (err != 0) {
-               printk(KERN_ERR "%s: failed to initialize firmware (err = %d)\n",
-                      dev->name, err);
+               dev_err(dev, "Failed to initialize firmware (err = %d)\n",
+                       err);
                goto out;
        }
 
-       err = determine_firmware(dev);
+       err = determine_fw_capabilities(priv);
        if (err != 0) {
-               printk(KERN_ERR "%s: Incompatible firmware, aborting\n",
-                      dev->name);
+               dev_err(dev, "Incompatible firmware, aborting\n");
                goto out;
        }
 
@@ -2347,147 +1999,41 @@ static int orinoco_init(struct net_device *dev)
                        priv->do_fw_download = 0;
 
                /* Check firmware version again */
-               err = determine_firmware(dev);
+               err = determine_fw_capabilities(priv);
                if (err != 0) {
-                       printk(KERN_ERR "%s: Incompatible firmware, aborting\n",
-                              dev->name);
+                       dev_err(dev, "Incompatible firmware, aborting\n");
                        goto out;
                }
        }
 
        if (priv->has_port3)
-               printk(KERN_DEBUG "%s: Ad-hoc demo mode supported\n",
-                      dev->name);
+               dev_info(dev, "Ad-hoc demo mode supported\n");
        if (priv->has_ibss)
-               printk(KERN_DEBUG "%s: IEEE standard IBSS ad-hoc mode supported\n",
-                      dev->name);
-       if (priv->has_wep) {
-               printk(KERN_DEBUG "%s: WEP supported, %s-bit key\n", dev->name,
-                      priv->has_big_wep ? "104" : "40");
-       }
+               dev_info(dev, "IEEE standard IBSS ad-hoc mode supported\n");
+       if (priv->has_wep)
+               dev_info(dev, "WEP supported, %s-bit key\n",
+                        priv->has_big_wep ? "104" : "40");
        if (priv->has_wpa) {
-               printk(KERN_DEBUG "%s: WPA-PSK supported\n", dev->name);
+               dev_info(dev, "WPA-PSK supported\n");
                if (orinoco_mic_init(priv)) {
-                       printk(KERN_ERR "%s: Failed to setup MIC crypto "
-                              "algorithm. Disabling WPA support\n", dev->name);
+                       dev_err(dev, "Failed to setup MIC crypto algorithm. "
+                               "Disabling WPA support\n");
                        priv->has_wpa = 0;
                }
        }
 
-       /* Now we have the firmware capabilities, allocate appropiate
-        * sized scan buffers */
-       if (orinoco_bss_data_allocate(priv))
-               goto out;
-       orinoco_bss_data_init(priv);
-
-       /* Get the MAC address */
-       err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNFOWNMACADDR,
-                             ETH_ALEN, NULL, dev->dev_addr);
-       if (err) {
-               printk(KERN_WARNING "%s: failed to read MAC address!\n",
-                      dev->name);
-               goto out;
-       }
-
-       printk(KERN_DEBUG "%s: MAC address %pM\n",
-              dev->name, dev->dev_addr);
-
-       /* Get the station name */
-       err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNFOWNNAME,
-                             sizeof(nickbuf), &reclen, &nickbuf);
-       if (err) {
-               printk(KERN_ERR "%s: failed to read station name\n",
-                      dev->name);
-               goto out;
-       }
-       if (nickbuf.len)
-               len = min(IW_ESSID_MAX_SIZE, (int)le16_to_cpu(nickbuf.len));
-       else
-               len = min(IW_ESSID_MAX_SIZE, 2 * reclen);
-       memcpy(priv->nick, &nickbuf.val, len);
-       priv->nick[len] = '\0';
-
-       printk(KERN_DEBUG "%s: Station name \"%s\"\n", dev->name, priv->nick);
-
-       err = orinoco_allocate_fid(dev);
-       if (err) {
-               printk(KERN_ERR "%s: failed to allocate NIC buffer!\n",
-                      dev->name);
-               goto out;
-       }
-
-       /* Get allowed channels */
-       err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CHANNELLIST,
-                                 &priv->channel_mask);
-       if (err) {
-               printk(KERN_ERR "%s: failed to read channel list!\n",
-                      dev->name);
-               goto out;
-       }
-
-       /* Get initial AP density */
-       err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFSYSTEMSCALE,
-                                 &priv->ap_density);
-       if (err || priv->ap_density < 1 || priv->ap_density > 3)
-               priv->has_sensitivity = 0;
-
-       /* Get initial RTS threshold */
-       err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFRTSTHRESHOLD,
-                                 &priv->rts_thresh);
-       if (err) {
-               printk(KERN_ERR "%s: failed to read RTS threshold!\n",
-                      dev->name);
+       err = orinoco_hw_read_card_settings(priv, wiphy->perm_addr);
+       if (err)
                goto out;
-       }
 
-       /* Get initial fragmentation settings */
-       if (priv->has_mwo)
-               err = hermes_read_wordrec(hw, USER_BAP,
-                                         HERMES_RID_CNFMWOROBUST_AGERE,
-                                         &priv->mwo_robust);
-       else
-               err = hermes_read_wordrec(hw, USER_BAP,
-                                         HERMES_RID_CNFFRAGMENTATIONTHRESHOLD,
-                                         &priv->frag_thresh);
+       err = orinoco_hw_allocate_fid(priv);
        if (err) {
-               printk(KERN_ERR "%s: failed to read fragmentation settings!\n",
-                      dev->name);
+               dev_err(dev, "Failed to allocate NIC buffer!\n");
                goto out;
        }
 
-       /* Power management setup */
-       if (priv->has_pm) {
-               priv->pm_on = 0;
-               priv->pm_mcast = 1;
-               err = hermes_read_wordrec(hw, USER_BAP,
-                                         HERMES_RID_CNFMAXSLEEPDURATION,
-                                         &priv->pm_period);
-               if (err) {
-                       printk(KERN_ERR "%s: failed to read power management period!\n",
-                              dev->name);
-                       goto out;
-               }
-               err = hermes_read_wordrec(hw, USER_BAP,
-                                         HERMES_RID_CNFPMHOLDOVERDURATION,
-                                         &priv->pm_timeout);
-               if (err) {
-                       printk(KERN_ERR "%s: failed to read power management timeout!\n",
-                              dev->name);
-                       goto out;
-               }
-       }
-
-       /* Preamble setup */
-       if (priv->has_preamble) {
-               err = hermes_read_wordrec(hw, USER_BAP,
-                                         HERMES_RID_CNFPREAMBLE_SYMBOL,
-                                         &priv->preamble);
-               if (err)
-                       goto out;
-       }
-
        /* Set up the default configuration */
-       priv->iw_mode = IW_MODE_INFRA;
+       priv->iw_mode = NL80211_IFTYPE_STATION;
        /* By default use IEEE/IBSS ad-hoc mode if we have it */
        priv->prefer_port3 = priv->has_port3 && (!priv->has_ibss);
        set_port_type(priv);
@@ -2502,20 +2048,25 @@ static int orinoco_init(struct net_device *dev)
        priv->wpa_ie_len = 0;
        priv->wpa_ie = NULL;
 
+       if (orinoco_wiphy_register(wiphy)) {
+               err = -ENODEV;
+               goto out;
+       }
+
        /* Make the hardware available, as long as it hasn't been
         * removed elsewhere (e.g. by PCMCIA hot unplug) */
        spin_lock_irq(&priv->lock);
        priv->hw_unavailable--;
        spin_unlock_irq(&priv->lock);
 
-       printk(KERN_DEBUG "%s: ready\n", dev->name);
+       dev_dbg(dev, "Ready\n");
 
  out:
        return err;
 }
+EXPORT_SYMBOL(orinoco_init);
 
 static const struct net_device_ops orinoco_netdev_ops = {
-       .ndo_init               = orinoco_init,
        .ndo_open               = orinoco_open,
        .ndo_stop               = orinoco_stop,
        .ndo_start_xmit         = orinoco_xmit,
@@ -2527,40 +2078,64 @@ static const struct net_device_ops orinoco_netdev_ops = {
        .ndo_get_stats          = orinoco_get_stats,
 };
 
-struct net_device
+/* Allocate private data.
+ *
+ * This driver has a number of structures associated with it
+ *  netdev - Net device structure for each network interface
+ *  wiphy - structure associated with wireless phy
+ *  wireless_dev (wdev) - structure for each wireless interface
+ *  hw - structure for hermes chip info
+ *  card - card specific structure for use by the card driver
+ *         (airport, orinoco_cs)
+ *  priv - orinoco private data
+ *  device - generic linux device structure
+ *
+ *  +---------+    +---------+
+ *  |  wiphy  |    | netdev  |
+ *  | +-------+    | +-------+
+ *  | | priv  |    | | wdev  |
+ *  | | +-----+    +-+-------+
+ *  | | | hw  |
+ *  | +-+-----+
+ *  | | card  |
+ *  +-+-------+
+ *
+ * priv has a link to netdev and device
+ * wdev has a link to wiphy
+ */
+struct orinoco_private
 *alloc_orinocodev(int sizeof_card,
                  struct device *device,
                  int (*hard_reset)(struct orinoco_private *),
                  int (*stop_fw)(struct orinoco_private *, int))
 {
-       struct net_device *dev;
        struct orinoco_private *priv;
+       struct wiphy *wiphy;
 
-       dev = alloc_etherdev(sizeof(struct orinoco_private) + sizeof_card);
-       if (!dev)
+       /* allocate wiphy
+        * NOTE: We only support a single virtual interface
+        *       but this may change when monitor mode is added
+        */
+       wiphy = wiphy_new(&orinoco_cfg_ops,
+                         sizeof(struct orinoco_private) + sizeof_card);
+       if (!wiphy)
                return NULL;
-       priv = netdev_priv(dev);
-       priv->ndev = dev;
+
+       priv = wiphy_priv(wiphy);
+       priv->dev = device;
+
        if (sizeof_card)
                priv->card = (void *)((unsigned long)priv
                                      + sizeof(struct orinoco_private));
        else
                priv->card = NULL;
-       priv->dev = device;
 
-       /* Setup / override net_device fields */
-       dev->netdev_ops = &orinoco_netdev_ops;
-       dev->watchdog_timeo = HZ; /* 1 second timeout */
-       dev->ethtool_ops = &orinoco_ethtool_ops;
-       dev->wireless_handlers = &orinoco_handler_def;
+       orinoco_wiphy_init(wiphy);
+
 #ifdef WIRELESS_SPY
        priv->wireless_data.spy_data = &priv->spy_data;
-       dev->wireless_data = &priv->wireless_data;
 #endif
 
-       /* Reserve space in skb for the SNAP header */
-       dev->hard_header_len += ENCAPS_OVERHEAD;
-
        /* Set up default callbacks */
        priv->hard_reset = hard_reset;
        priv->stop_fw = stop_fw;
@@ -2576,9 +2151,12 @@ struct net_device
 
        INIT_LIST_HEAD(&priv->rx_list);
        tasklet_init(&priv->rx_tasklet, orinoco_rx_isr_tasklet,
-                    (unsigned long) dev);
+                    (unsigned long) priv);
+
+       spin_lock_init(&priv->scan_lock);
+       INIT_LIST_HEAD(&priv->scan_list);
+       INIT_WORK(&priv->process_scan, orinoco_process_scan_results);
 
-       netif_carrier_off(dev);
        priv->last_linkstatus = 0xffff;
 
 #if defined(CONFIG_HERMES_CACHE_FW_ON_INIT) || defined(CONFIG_PM_SLEEP)
@@ -2589,14 +2167,91 @@ struct net_device
        /* Register PM notifiers */
        orinoco_register_pm_notifier(priv);
 
-       return dev;
+       return priv;
 }
 EXPORT_SYMBOL(alloc_orinocodev);
 
-void free_orinocodev(struct net_device *dev)
+/* We can only support a single interface. We provide a separate
+ * function to set it up to distinguish between hardware
+ * initialisation and interface setup.
+ *
+ * The base_addr and irq parameters are passed on to netdev for use
+ * with SIOCGIFMAP.
+ */
+int orinoco_if_add(struct orinoco_private *priv,
+                  unsigned long base_addr,
+                  unsigned int irq)
+{
+       struct wiphy *wiphy = priv_to_wiphy(priv);
+       struct wireless_dev *wdev;
+       struct net_device *dev;
+       int ret;
+
+       dev = alloc_etherdev(sizeof(struct wireless_dev));
+
+       if (!dev)
+               return -ENOMEM;
+
+       /* Initialise wireless_dev */
+       wdev = netdev_priv(dev);
+       wdev->wiphy = wiphy;
+       wdev->iftype = NL80211_IFTYPE_STATION;
+
+       /* Setup / override net_device fields */
+       dev->ieee80211_ptr = wdev;
+       dev->netdev_ops = &orinoco_netdev_ops;
+       dev->watchdog_timeo = HZ; /* 1 second timeout */
+       dev->ethtool_ops = &orinoco_ethtool_ops;
+       dev->wireless_handlers = &orinoco_handler_def;
+#ifdef WIRELESS_SPY
+       dev->wireless_data = &priv->wireless_data;
+#endif
+       /* we use the default eth_mac_addr for setting the MAC addr */
+
+       /* Reserve space in skb for the SNAP header */
+       dev->hard_header_len += ENCAPS_OVERHEAD;
+
+       netif_carrier_off(dev);
+
+       memcpy(dev->dev_addr, wiphy->perm_addr, ETH_ALEN);
+
+       dev->base_addr = base_addr;
+       dev->irq = irq;
+
+       SET_NETDEV_DEV(dev, priv->dev);
+       ret = register_netdev(dev);
+       if (ret)
+               goto fail;
+
+       priv->ndev = dev;
+
+       /* Report what we've done */
+       dev_dbg(priv->dev, "Registerred interface %s.\n", dev->name);
+
+       return 0;
+
+ fail:
+       free_netdev(dev);
+       return ret;
+}
+EXPORT_SYMBOL(orinoco_if_add);
+
+void orinoco_if_del(struct orinoco_private *priv)
+{
+       struct net_device *dev = priv->ndev;
+
+       unregister_netdev(dev);
+       free_netdev(dev);
+}
+EXPORT_SYMBOL(orinoco_if_del);
+
+void free_orinocodev(struct orinoco_private *priv)
 {
-       struct orinoco_private *priv = netdev_priv(dev);
+       struct wiphy *wiphy = priv_to_wiphy(priv);
        struct orinoco_rx_data *rx_data, *temp;
+       struct orinoco_scan_data *sd, *sdtemp;
+
+       wiphy_unregister(wiphy);
 
        /* If the tasklet is scheduled when we call tasklet_kill it
         * will run one final time. However the tasklet will only
@@ -2612,21 +2267,80 @@ void free_orinocodev(struct net_device *dev)
                kfree(rx_data);
        }
 
+       cancel_work_sync(&priv->process_scan);
+       /* Explicitly drain priv->scan_list */
+       list_for_each_entry_safe(sd, sdtemp, &priv->scan_list, list) {
+               list_del(&sd->list);
+
+               if ((sd->len > 0) && sd->buf)
+                       kfree(sd->buf);
+               kfree(sd);
+       }
+
        orinoco_unregister_pm_notifier(priv);
        orinoco_uncache_fw(priv);
 
        priv->wpa_ie_len = 0;
        kfree(priv->wpa_ie);
        orinoco_mic_free(priv);
-       orinoco_bss_data_free(priv);
-       free_netdev(dev);
+       wiphy_free(wiphy);
 }
 EXPORT_SYMBOL(free_orinocodev);
 
+int orinoco_up(struct orinoco_private *priv)
+{
+       struct net_device *dev = priv->ndev;
+       unsigned long flags;
+       int err;
+
+       spin_lock_irqsave(&priv->lock, flags);
+
+       err = orinoco_reinit_firmware(priv);
+       if (err) {
+               printk(KERN_ERR "%s: Error %d re-initializing firmware\n",
+                      dev->name, err);
+               goto exit;
+       }
+
+       netif_device_attach(dev);
+       priv->hw_unavailable--;
+
+       if (priv->open && !priv->hw_unavailable) {
+               err = __orinoco_up(priv);
+               if (err)
+                       printk(KERN_ERR "%s: Error %d restarting card\n",
+                              dev->name, err);
+       }
+
+exit:
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       return 0;
+}
+EXPORT_SYMBOL(orinoco_up);
+
+void orinoco_down(struct orinoco_private *priv)
+{
+       struct net_device *dev = priv->ndev;
+       unsigned long flags;
+       int err;
+
+       spin_lock_irqsave(&priv->lock, flags);
+       err = __orinoco_down(priv);
+       if (err)
+               printk(KERN_WARNING "%s: Error %d downing interface\n",
+                      dev->name, err);
+
+       netif_device_detach(dev);
+       priv->hw_unavailable++;
+       spin_unlock_irqrestore(&priv->lock, flags);
+}
+EXPORT_SYMBOL(orinoco_down);
+
 static void orinoco_get_drvinfo(struct net_device *dev,
                                struct ethtool_drvinfo *info)
 {
-       struct orinoco_private *priv = netdev_priv(dev);
+       struct orinoco_private *priv = ndev_priv(dev);
 
        strncpy(info->driver, DRIVER_NAME, sizeof(info->driver) - 1);
        strncpy(info->version, DRIVER_VERSION, sizeof(info->version) - 1);
index af2bae4..21ab36c 100644 (file)
@@ -29,10 +29,9 @@ struct net_device;
 struct work_struct;
 
 void set_port_type(struct orinoco_private *priv);
-int __orinoco_program_rids(struct net_device *dev);
+int orinoco_commit(struct orinoco_private *priv);
 void orinoco_reset(struct work_struct *work);
 
-
 /* Information element helpers - find a home for these... */
 static inline u8 *orinoco_get_ie(u8 *data, size_t len,
                                 enum ieee80211_eid eid)
index 8e5a72c..5f4f5c9 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/netdevice.h>
 #include <linux/wireless.h>
 #include <net/iw_handler.h>
+#include <net/cfg80211.h>
 
 #include "hermes.h"
 
@@ -47,18 +48,6 @@ typedef enum {
        FIRMWARE_TYPE_SYMBOL
 } fwtype_t;
 
-struct bss_element {
-       union hermes_scan_info bss;
-       unsigned long last_scanned;
-       struct list_head list;
-};
-
-struct xbss_element {
-       struct agere_ext_scan_info bss;
-       unsigned long last_scanned;
-       struct list_head list;
-};
-
 struct firmware;
 
 struct orinoco_private {
@@ -67,6 +56,10 @@ struct orinoco_private {
        int (*hard_reset)(struct orinoco_private *);
        int (*stop_fw)(struct orinoco_private *, int);
 
+       struct ieee80211_supported_band band;
+       struct ieee80211_channel channels[14];
+       u32 cipher_suites[3];
+
        /* Synchronisation stuff */
        spinlock_t lock;
        int hw_unavailable;
@@ -116,7 +109,7 @@ struct orinoco_private {
        unsigned int broken_monitor:1;
 
        /* Configuration paramaters */
-       u32 iw_mode;
+       enum nl80211_iftype iw_mode;
        int prefer_port3;
        u16 encode_alg, wep_restrict, tx_key;
        struct orinoco_key keys[ORINOCO_MAX_KEYS];
@@ -140,12 +133,10 @@ struct orinoco_private {
        int promiscuous, mc_count;
 
        /* Scanning support */
-       struct list_head bss_list;
-       struct list_head bss_free_list;
-       void *bss_xbss_data;
-
-       int     scan_inprogress;        /* Scan pending... */
-       u32     scan_mode;              /* Type of scan done */
+       struct cfg80211_scan_request *scan_request;
+       struct work_struct process_scan;
+       struct list_head scan_list;
+       spinlock_t scan_lock; /* protects the scan list */
 
        /* WPA support */
        u8 *wpa_ie;
@@ -182,14 +173,18 @@ extern int orinoco_debug;
 /* Exported prototypes                                              */
 /********************************************************************/
 
-extern struct net_device *alloc_orinocodev(
+extern struct orinoco_private *alloc_orinocodev(
        int sizeof_card, struct device *device,
        int (*hard_reset)(struct orinoco_private *),
        int (*stop_fw)(struct orinoco_private *, int));
-extern void free_orinocodev(struct net_device *dev);
-extern int __orinoco_up(struct net_device *dev);
-extern int __orinoco_down(struct net_device *dev);
-extern int orinoco_reinit_firmware(struct net_device *dev);
+extern void free_orinocodev(struct orinoco_private *priv);
+extern int orinoco_init(struct orinoco_private *priv);
+extern int orinoco_if_add(struct orinoco_private *priv,
+                         unsigned long base_addr,
+                         unsigned int irq);
+extern void orinoco_if_del(struct orinoco_private *priv);
+extern int orinoco_up(struct orinoco_private *priv);
+extern void orinoco_down(struct orinoco_private *priv);
 extern irqreturn_t orinoco_interrupt(int irq, void *dev_id);
 
 /********************************************************************/
@@ -215,4 +210,10 @@ static inline void orinoco_unlock(struct orinoco_private *priv,
        spin_unlock_irqrestore(&priv->lock, *flags);
 }
 
+/*** Navigate from net_device to orinoco_private ***/
+static inline struct orinoco_private *ndev_priv(struct net_device *dev)
+{
+       struct wireless_dev *wdev = netdev_priv(dev);
+       return wdev_priv(wdev);
+}
 #endif /* _ORINOCO_H */
index b381aed..38c1c9d 100644 (file)
@@ -106,26 +106,24 @@ orinoco_cs_hard_reset(struct orinoco_private *priv)
 static int
 orinoco_cs_probe(struct pcmcia_device *link)
 {
-       struct net_device *dev;
        struct orinoco_private *priv;
        struct orinoco_pccard *card;
 
-       dev = alloc_orinocodev(sizeof(*card), &handle_to_dev(link),
-                              orinoco_cs_hard_reset, NULL);
-       if (!dev)
+       priv = alloc_orinocodev(sizeof(*card), &handle_to_dev(link),
+                               orinoco_cs_hard_reset, NULL);
+       if (!priv)
                return -ENOMEM;
-       priv = netdev_priv(dev);
        card = priv->card;
 
        /* Link both structures together */
        card->p_dev = link;
-       link->priv = dev;
+       link->priv = priv;
 
        /* Interrupt setup */
        link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING | IRQ_HANDLE_PRESENT;
        link->irq.IRQInfo1 = IRQ_LEVEL_ID;
        link->irq.Handler = orinoco_interrupt;
-       link->irq.Instance = dev;
+       link->irq.Instance = priv;
 
        /* General socket configuration defaults can go here.  In this
         * client, we assume very little, and rely on the CIS for
@@ -146,14 +144,14 @@ orinoco_cs_probe(struct pcmcia_device *link)
  */
 static void orinoco_cs_detach(struct pcmcia_device *link)
 {
-       struct net_device *dev = link->priv;
+       struct orinoco_private *priv = link->priv;
 
        if (link->dev_node)
-               unregister_netdev(dev);
+               orinoco_if_del(priv);
 
        orinoco_cs_release(link);
 
-       free_orinocodev(dev);
+       free_orinocodev(priv);
 }                              /* orinoco_cs_detach */
 
 /*
@@ -239,8 +237,7 @@ next_entry:
 static int
 orinoco_cs_config(struct pcmcia_device *link)
 {
-       struct net_device *dev = link->priv;
-       struct orinoco_private *priv = netdev_priv(dev);
+       struct orinoco_private *priv = link->priv;
        struct orinoco_pccard *card = priv->card;
        hermes_t *hw = &priv->hw;
        int last_fn, last_ret;
@@ -295,29 +292,27 @@ orinoco_cs_config(struct pcmcia_device *link)
                 pcmcia_request_configuration(link, &link->conf));
 
        /* Ok, we have the configuration, prepare to register the netdev */
-       dev->base_addr = link->io.BasePort1;
-       dev->irq = link->irq.AssignedIRQ;
        card->node.major = card->node.minor = 0;
 
-       SET_NETDEV_DEV(dev, &handle_to_dev(link));
-       /* Tell the stack we exist */
-       if (register_netdev(dev) != 0) {
-               printk(KERN_ERR PFX "register_netdev() failed\n");
+       /* Initialise the main driver */
+       if (orinoco_init(priv) != 0) {
+               printk(KERN_ERR PFX "orinoco_init() failed\n");
+               goto failed;
+       }
+
+       /* Register an interface with the stack */
+       if (orinoco_if_add(priv, link->io.BasePort1,
+                          link->irq.AssignedIRQ) != 0) {
+               printk(KERN_ERR PFX "orinoco_if_add() failed\n");
                goto failed;
        }
 
        /* At this point, the dev_node_t structure(s) needs to be
         * initialized and arranged in a linked list at link->dev_node. */
-       strcpy(card->node.dev_name, dev->name);
+       strcpy(card->node.dev_name, priv->ndev->name);
        link->dev_node = &card->node; /* link->dev_node being non-NULL is also
                                       * used to indicate that the
                                       * net_device has been registered */
-
-       /* Finally, report what we've done */
-       printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s, irq %d, io "
-              "0x%04x-0x%04x\n", dev->name, dev_name(dev->dev.parent),
-              link->irq.AssignedIRQ, link->io.BasePort1,
-              link->io.BasePort1 + link->io.NumPorts1 - 1);
        return 0;
 
  cs_failed:
@@ -336,8 +331,7 @@ orinoco_cs_config(struct pcmcia_device *link)
 static void
 orinoco_cs_release(struct pcmcia_device *link)
 {
-       struct net_device *dev = link->priv;
-       struct orinoco_private *priv = netdev_priv(dev);
+       struct orinoco_private *priv = link->priv;
        unsigned long flags;
 
        /* We're committed to taking the device away now, so mark the
@@ -353,62 +347,26 @@ orinoco_cs_release(struct pcmcia_device *link)
 
 static int orinoco_cs_suspend(struct pcmcia_device *link)
 {
-       struct net_device *dev = link->priv;
-       struct orinoco_private *priv = netdev_priv(dev);
+       struct orinoco_private *priv = link->priv;
        struct orinoco_pccard *card = priv->card;
-       int err = 0;
-       unsigned long flags;
 
        /* This is probably racy, but I can't think of
           a better way, short of rewriting the PCMCIA
           layer to not suck :-( */
-       if (!test_bit(0, &card->hard_reset_in_progress)) {
-               spin_lock_irqsave(&priv->lock, flags);
-
-               err = __orinoco_down(dev);
-               if (err)
-                       printk(KERN_WARNING "%s: Error %d downing interface\n",
-                              dev->name, err);
-
-               netif_device_detach(dev);
-               priv->hw_unavailable++;
-
-               spin_unlock_irqrestore(&priv->lock, flags);
-       }
+       if (!test_bit(0, &card->hard_reset_in_progress))
+               orinoco_down(priv);
 
        return 0;
 }
 
 static int orinoco_cs_resume(struct pcmcia_device *link)
 {
-       struct net_device *dev = link->priv;
-       struct orinoco_private *priv = netdev_priv(dev);
+       struct orinoco_private *priv = link->priv;
        struct orinoco_pccard *card = priv->card;
        int err = 0;
-       unsigned long flags;
-
-       if (!test_bit(0, &card->hard_reset_in_progress)) {
-               err = orinoco_reinit_firmware(dev);
-               if (err) {
-                       printk(KERN_ERR "%s: Error %d re-initializing firmware\n",
-                              dev->name, err);
-                       return -EIO;
-               }
-
-               spin_lock_irqsave(&priv->lock, flags);
 
-               netif_device_attach(dev);
-               priv->hw_unavailable--;
-
-               if (priv->open && !priv->hw_unavailable) {
-                       err = __orinoco_up(dev);
-                       if (err)
-                               printk(KERN_ERR "%s: Error %d restarting card\n",
-                                      dev->name, err);
-               }
-
-               spin_unlock_irqrestore(&priv->lock, flags);
-       }
+       if (!test_bit(0, &card->hard_reset_in_progress))
+               err = orinoco_up(priv);
 
        return err;
 }
index b017262..c13a4c3 100644 (file)
@@ -144,7 +144,6 @@ static int orinoco_nortel_init_one(struct pci_dev *pdev,
        int err;
        struct orinoco_private *priv;
        struct orinoco_pci_card *card;
-       struct net_device *dev;
        void __iomem *hermes_io, *bridge_io, *attr_io;
 
        err = pci_enable_device(pdev);
@@ -181,24 +180,22 @@ static int orinoco_nortel_init_one(struct pci_dev *pdev,
        }
 
        /* Allocate network device */
-       dev = alloc_orinocodev(sizeof(*card), &pdev->dev,
-                              orinoco_nortel_cor_reset, NULL);
-       if (!dev) {
+       priv = alloc_orinocodev(sizeof(*card), &pdev->dev,
+                               orinoco_nortel_cor_reset, NULL);
+       if (!priv) {
                printk(KERN_ERR PFX "Cannot allocate network device\n");
                err = -ENOMEM;
                goto fail_alloc;
        }
 
-       priv = netdev_priv(dev);
        card = priv->card;
        card->bridge_io = bridge_io;
        card->attr_io = attr_io;
-       SET_NETDEV_DEV(dev, &pdev->dev);
 
        hermes_struct_init(&priv->hw, hermes_io, HERMES_16BIT_REGSPACING);
 
        err = request_irq(pdev->irq, orinoco_interrupt, IRQF_SHARED,
-                         dev->name, dev);
+                         DRIVER_NAME, priv);
        if (err) {
                printk(KERN_ERR PFX "Cannot allocate IRQ %d\n", pdev->irq);
                err = -EBUSY;
@@ -217,24 +214,28 @@ static int orinoco_nortel_init_one(struct pci_dev *pdev,
                goto fail;
        }
 
-       err = register_netdev(dev);
+       err = orinoco_init(priv);
        if (err) {
-               printk(KERN_ERR PFX "Cannot register network device\n");
+               printk(KERN_ERR PFX "orinoco_init() failed\n");
                goto fail;
        }
 
-       pci_set_drvdata(pdev, dev);
-       printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s\n", dev->name,
-              pci_name(pdev));
+       err = orinoco_if_add(priv, 0, 0);
+       if (err) {
+               printk(KERN_ERR PFX "orinoco_if_add() failed\n");
+               goto fail;
+       }
+
+       pci_set_drvdata(pdev, priv);
 
        return 0;
 
  fail:
-       free_irq(pdev->irq, dev);
+       free_irq(pdev->irq, priv);
 
  fail_irq:
        pci_set_drvdata(pdev, NULL);
-       free_orinocodev(dev);
+       free_orinocodev(priv);
 
  fail_alloc:
        pci_iounmap(pdev, hermes_io);
@@ -256,17 +257,16 @@ static int orinoco_nortel_init_one(struct pci_dev *pdev,
 
 static void __devexit orinoco_nortel_remove_one(struct pci_dev *pdev)
 {
-       struct net_device *dev = pci_get_drvdata(pdev);
-       struct orinoco_private *priv = netdev_priv(dev);
+       struct orinoco_private *priv = pci_get_drvdata(pdev);
        struct orinoco_pci_card *card = priv->card;
 
        /* Clear LEDs */
        iowrite16(0, card->bridge_io + 10);
 
-       unregister_netdev(dev);
-       free_irq(pdev->irq, dev);
+       orinoco_if_del(priv);
+       free_irq(pdev->irq, priv);
        pci_set_drvdata(pdev, NULL);
-       free_orinocodev(dev);
+       free_orinocodev(priv);
        pci_iounmap(pdev, priv->hw.iobase);
        pci_iounmap(pdev, card->attr_io);
        pci_iounmap(pdev, card->bridge_io);
index 78cafff..fea7781 100644 (file)
@@ -116,7 +116,6 @@ static int orinoco_pci_init_one(struct pci_dev *pdev,
        int err;
        struct orinoco_private *priv;
        struct orinoco_pci_card *card;
-       struct net_device *dev;
        void __iomem *hermes_io;
 
        err = pci_enable_device(pdev);
@@ -139,22 +138,20 @@ static int orinoco_pci_init_one(struct pci_dev *pdev,
        }
 
        /* Allocate network device */
-       dev = alloc_orinocodev(sizeof(*card), &pdev->dev,
-                              orinoco_pci_cor_reset, NULL);
-       if (!dev) {
+       priv = alloc_orinocodev(sizeof(*card), &pdev->dev,
+                               orinoco_pci_cor_reset, NULL);
+       if (!priv) {
                printk(KERN_ERR PFX "Cannot allocate network device\n");
                err = -ENOMEM;
                goto fail_alloc;
        }
 
-       priv = netdev_priv(dev);
        card = priv->card;
-       SET_NETDEV_DEV(dev, &pdev->dev);
 
        hermes_struct_init(&priv->hw, hermes_io, HERMES_32BIT_REGSPACING);
 
        err = request_irq(pdev->irq, orinoco_interrupt, IRQF_SHARED,
-                         dev->name, dev);
+                         DRIVER_NAME, priv);
        if (err) {
                printk(KERN_ERR PFX "Cannot allocate IRQ %d\n", pdev->irq);
                err = -EBUSY;
@@ -167,24 +164,28 @@ static int orinoco_pci_init_one(struct pci_dev *pdev,
                goto fail;
        }
 
-       err = register_netdev(dev);
+       err = orinoco_init(priv);
        if (err) {
-               printk(KERN_ERR PFX "Cannot register network device\n");
+               printk(KERN_ERR PFX "orinoco_init() failed\n");
                goto fail;
        }
 
-       pci_set_drvdata(pdev, dev);
-       printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s\n", dev->name,
-              pci_name(pdev));
+       err = orinoco_if_add(priv, 0, 0);
+       if (err) {
+               printk(KERN_ERR PFX "orinoco_if_add() failed\n");
+               goto fail;
+       }
+
+       pci_set_drvdata(pdev, priv);
 
        return 0;
 
  fail:
-       free_irq(pdev->irq, dev);
+       free_irq(pdev->irq, priv);
 
  fail_irq:
        pci_set_drvdata(pdev, NULL);
-       free_orinocodev(dev);
+       free_orinocodev(priv);
 
  fail_alloc:
        pci_iounmap(pdev, hermes_io);
@@ -200,13 +201,12 @@ static int orinoco_pci_init_one(struct pci_dev *pdev,
 
 static void __devexit orinoco_pci_remove_one(struct pci_dev *pdev)
 {
-       struct net_device *dev = pci_get_drvdata(pdev);
-       struct orinoco_private *priv = netdev_priv(dev);
+       struct orinoco_private *priv = pci_get_drvdata(pdev);
 
-       unregister_netdev(dev);
-       free_irq(pdev->irq, dev);
+       orinoco_if_del(priv);
+       free_irq(pdev->irq, priv);
        pci_set_drvdata(pdev, NULL);
-       free_orinocodev(dev);
+       free_orinocodev(priv);
        pci_iounmap(pdev, priv->hw.iobase);
        pci_release_regions(pdev);
        pci_disable_device(pdev);
index c655b4a..ea7231a 100644 (file)
@@ -21,30 +21,10 @@ struct orinoco_pci_card {
 #ifdef CONFIG_PM
 static int orinoco_pci_suspend(struct pci_dev *pdev, pm_message_t state)
 {
-       struct net_device *dev = pci_get_drvdata(pdev);
-       struct orinoco_private *priv = netdev_priv(dev);
-       unsigned long flags;
-       int err;
-
-       err = orinoco_lock(priv, &flags);
-       if (err) {
-               printk(KERN_ERR "%s: cannot lock hardware for suspend\n",
-                      dev->name);
-               return err;
-       }
-
-       err = __orinoco_down(dev);
-       if (err)
-               printk(KERN_WARNING "%s: error %d bringing interface down "
-                      "for suspend\n", dev->name, err);
-
-       netif_device_detach(dev);
-
-       priv->hw_unavailable++;
-
-       orinoco_unlock(priv, &flags);
+       struct orinoco_private *priv = pci_get_drvdata(pdev);
 
-       free_irq(pdev->irq, dev);
+       orinoco_down(priv);
+       free_irq(pdev->irq, priv);
        pci_save_state(pdev);
        pci_disable_device(pdev);
        pci_set_power_state(pdev, PCI_D3hot);
@@ -54,9 +34,8 @@ static int orinoco_pci_suspend(struct pci_dev *pdev, pm_message_t state)
 
 static int orinoco_pci_resume(struct pci_dev *pdev)
 {
-       struct net_device *dev = pci_get_drvdata(pdev);
-       struct orinoco_private *priv = netdev_priv(dev);
-       unsigned long flags;
+       struct orinoco_private *priv = pci_get_drvdata(pdev);
+       struct net_device *dev = priv->ndev;
        int err;
 
        pci_set_power_state(pdev, 0);
@@ -69,7 +48,7 @@ static int orinoco_pci_resume(struct pci_dev *pdev)
        pci_restore_state(pdev);
 
        err = request_irq(pdev->irq, orinoco_interrupt, IRQF_SHARED,
-                         dev->name, dev);
+                         dev->name, priv);
        if (err) {
                printk(KERN_ERR "%s: cannot re-allocate IRQ on resume\n",
                       dev->name);
@@ -77,29 +56,9 @@ static int orinoco_pci_resume(struct pci_dev *pdev)
                return -EBUSY;
        }
 
-       err = orinoco_reinit_firmware(dev);
-       if (err) {
-               printk(KERN_ERR "%s: error %d re-initializing firmware "
-                      "on resume\n", dev->name, err);
-               return err;
-       }
-
-       spin_lock_irqsave(&priv->lock, flags);
-
-       netif_device_attach(dev);
+       err = orinoco_up(priv);
 
-       priv->hw_unavailable--;
-
-       if (priv->open && (!priv->hw_unavailable)) {
-               err = __orinoco_up(dev);
-               if (err)
-                       printk(KERN_ERR "%s: Error %d restarting card on resume\n",
-                              dev->name, err);
-       }
-
-       spin_unlock_irqrestore(&priv->lock, flags);
-
-       return 0;
+       return err;
 }
 #else
 #define orinoco_pci_suspend NULL
index a2a4471..3f2942a 100644 (file)
@@ -183,7 +183,6 @@ static int orinoco_plx_init_one(struct pci_dev *pdev,
        int err;
        struct orinoco_private *priv;
        struct orinoco_pci_card *card;
-       struct net_device *dev;
        void __iomem *hermes_io, *attr_io, *bridge_io;
 
        err = pci_enable_device(pdev);
@@ -220,24 +219,22 @@ static int orinoco_plx_init_one(struct pci_dev *pdev,
        }
 
        /* Allocate network device */
-       dev = alloc_orinocodev(sizeof(*card), &pdev->dev,
-                              orinoco_plx_cor_reset, NULL);
-       if (!dev) {
+       priv = alloc_orinocodev(sizeof(*card), &pdev->dev,
+                               orinoco_plx_cor_reset, NULL);
+       if (!priv) {
                printk(KERN_ERR PFX "Cannot allocate network device\n");
                err = -ENOMEM;
                goto fail_alloc;
        }
 
-       priv = netdev_priv(dev);
        card = priv->card;
        card->bridge_io = bridge_io;
        card->attr_io = attr_io;
-       SET_NETDEV_DEV(dev, &pdev->dev);
 
        hermes_struct_init(&priv->hw, hermes_io, HERMES_16BIT_REGSPACING);
 
        err = request_irq(pdev->irq, orinoco_interrupt, IRQF_SHARED,
-                         dev->name, dev);
+                         DRIVER_NAME, priv);
        if (err) {
                printk(KERN_ERR PFX "Cannot allocate IRQ %d\n", pdev->irq);
                err = -EBUSY;
@@ -256,24 +253,28 @@ static int orinoco_plx_init_one(struct pci_dev *pdev,
                goto fail;
        }
 
-       err = register_netdev(dev);
+       err = orinoco_init(priv);
        if (err) {
-               printk(KERN_ERR PFX "Cannot register network device\n");
+               printk(KERN_ERR PFX "orinoco_init() failed\n");
                goto fail;
        }
 
-       pci_set_drvdata(pdev, dev);
-       printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s\n", dev->name,
-              pci_name(pdev));
+       err = orinoco_if_add(priv, 0, 0);
+       if (err) {
+               printk(KERN_ERR PFX "orinoco_if_add() failed\n");
+               goto fail;
+       }
+
+       pci_set_drvdata(pdev, priv);
 
        return 0;
 
  fail:
-       free_irq(pdev->irq, dev);
+       free_irq(pdev->irq, priv);
 
  fail_irq:
        pci_set_drvdata(pdev, NULL);
-       free_orinocodev(dev);
+       free_orinocodev(priv);
 
  fail_alloc:
        pci_iounmap(pdev, hermes_io);
@@ -295,14 +296,13 @@ static int orinoco_plx_init_one(struct pci_dev *pdev,
 
 static void __devexit orinoco_plx_remove_one(struct pci_dev *pdev)
 {
-       struct net_device *dev = pci_get_drvdata(pdev);
-       struct orinoco_private *priv = netdev_priv(dev);
+       struct orinoco_private *priv = pci_get_drvdata(pdev);
        struct orinoco_pci_card *card = priv->card;
 
-       unregister_netdev(dev);
-       free_irq(pdev->irq, dev);
+       orinoco_if_del(priv);
+       free_irq(pdev->irq, priv);
        pci_set_drvdata(pdev, NULL);
-       free_orinocodev(dev);
+       free_orinocodev(priv);
        pci_iounmap(pdev, priv->hw.iobase);
        pci_iounmap(pdev, card->attr_io);
        pci_iounmap(pdev, card->bridge_io);
index cda0e6e..d345254 100644 (file)
@@ -94,7 +94,6 @@ static int orinoco_tmd_init_one(struct pci_dev *pdev,
        int err;
        struct orinoco_private *priv;
        struct orinoco_pci_card *card;
-       struct net_device *dev;
        void __iomem *hermes_io, *bridge_io;
 
        err = pci_enable_device(pdev);
@@ -124,23 +123,21 @@ static int orinoco_tmd_init_one(struct pci_dev *pdev,
        }
 
        /* Allocate network device */
-       dev = alloc_orinocodev(sizeof(*card), &pdev->dev,
-                              orinoco_tmd_cor_reset, NULL);
-       if (!dev) {
+       priv = alloc_orinocodev(sizeof(*card), &pdev->dev,
+                               orinoco_tmd_cor_reset, NULL);
+       if (!priv) {
                printk(KERN_ERR PFX "Cannot allocate network device\n");
                err = -ENOMEM;
                goto fail_alloc;
        }
 
-       priv = netdev_priv(dev);
        card = priv->card;
        card->bridge_io = bridge_io;
-       SET_NETDEV_DEV(dev, &pdev->dev);
 
        hermes_struct_init(&priv->hw, hermes_io, HERMES_16BIT_REGSPACING);
 
        err = request_irq(pdev->irq, orinoco_interrupt, IRQF_SHARED,
-                         dev->name, dev);
+                         DRIVER_NAME, priv);
        if (err) {
                printk(KERN_ERR PFX "Cannot allocate IRQ %d\n", pdev->irq);
                err = -EBUSY;
@@ -153,24 +150,28 @@ static int orinoco_tmd_init_one(struct pci_dev *pdev,
                goto fail;
        }
 
-       err = register_netdev(dev);
+       err = orinoco_init(priv);
        if (err) {
-               printk(KERN_ERR PFX "Cannot register network device\n");
+               printk(KERN_ERR PFX "orinoco_init() failed\n");
                goto fail;
        }
 
-       pci_set_drvdata(pdev, dev);
-       printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s\n", dev->name,
-              pci_name(pdev));
+       err = orinoco_if_add(priv, 0, 0);
+       if (err) {
+               printk(KERN_ERR PFX "orinoco_if_add() failed\n");
+               goto fail;
+       }
+
+       pci_set_drvdata(pdev, priv);
 
        return 0;
 
  fail:
-       free_irq(pdev->irq, dev);
+       free_irq(pdev->irq, priv);
 
  fail_irq:
        pci_set_drvdata(pdev, NULL);
-       free_orinocodev(dev);
+       free_orinocodev(priv);
 
  fail_alloc:
        pci_iounmap(pdev, hermes_io);
@@ -189,14 +190,13 @@ static int orinoco_tmd_init_one(struct pci_dev *pdev,
 
 static void __devexit orinoco_tmd_remove_one(struct pci_dev *pdev)
 {
-       struct net_device *dev = pci_get_drvdata(pdev);
-       struct orinoco_private *priv = netdev_priv(dev);
+       struct orinoco_private *priv = pci_get_drvdata(pdev);
        struct orinoco_pci_card *card = priv->card;
 
-       unregister_netdev(dev);
-       free_irq(pdev->irq, dev);
+       orinoco_if_del(priv);
+       free_irq(pdev->irq, priv);
        pci_set_drvdata(pdev, NULL);
-       free_orinocodev(dev);
+       free_orinocodev(priv);
        pci_iounmap(pdev, priv->hw.iobase);
        pci_iounmap(pdev, card->bridge_io);
        pci_release_regions(pdev);
index 89d699d..d2f10e9 100644 (file)
 
 #include <linux/kernel.h>
 #include <linux/string.h>
-#include <linux/etherdevice.h>
+#include <linux/ieee80211.h>
+#include <net/cfg80211.h>
 
 #include "hermes.h"
 #include "orinoco.h"
+#include "main.h"
 
 #include "scan.h"
 
-#define ORINOCO_MAX_BSS_COUNT  64
+#define ZERO_DBM_OFFSET 0x95
+#define MAX_SIGNAL_LEVEL 0x8A
+#define MIN_SIGNAL_LEVEL 0x2F
 
-#define PRIV_BSS       ((struct bss_element *)priv->bss_xbss_data)
-#define PRIV_XBSS      ((struct xbss_element *)priv->bss_xbss_data)
+#define SIGNAL_TO_DBM(x)                                       \
+       (clamp_t(s32, (x), MIN_SIGNAL_LEVEL, MAX_SIGNAL_LEVEL)  \
+        - ZERO_DBM_OFFSET)
+#define SIGNAL_TO_MBM(x) (SIGNAL_TO_DBM(x) * 100)
 
-int orinoco_bss_data_allocate(struct orinoco_private *priv)
+static int symbol_build_supp_rates(u8 *buf, const __le16 *rates)
 {
-       if (priv->bss_xbss_data)
-               return 0;
-
-       if (priv->has_ext_scan)
-               priv->bss_xbss_data = kzalloc(ORINOCO_MAX_BSS_COUNT *
-                                             sizeof(struct xbss_element),
-                                             GFP_KERNEL);
-       else
-               priv->bss_xbss_data = kzalloc(ORINOCO_MAX_BSS_COUNT *
-                                             sizeof(struct bss_element),
-                                             GFP_KERNEL);
-
-       if (!priv->bss_xbss_data) {
-               printk(KERN_WARNING "Out of memory allocating beacons");
-               return -ENOMEM;
+       int i;
+       u8 rate;
+
+       buf[0] = WLAN_EID_SUPP_RATES;
+       for (i = 0; i < 5; i++) {
+               rate = le16_to_cpu(rates[i]);
+               /* NULL terminated */
+               if (rate == 0x0)
+                       break;
+               buf[i + 2] = rate;
        }
-       return 0;
-}
+       buf[1] = i;
 
-void orinoco_bss_data_free(struct orinoco_private *priv)
-{
-       kfree(priv->bss_xbss_data);
-       priv->bss_xbss_data = NULL;
+       return i + 2;
 }
 
-void orinoco_bss_data_init(struct orinoco_private *priv)
+static int prism_build_supp_rates(u8 *buf, const u8 *rates)
 {
        int i;
 
-       INIT_LIST_HEAD(&priv->bss_free_list);
-       INIT_LIST_HEAD(&priv->bss_list);
-       if (priv->has_ext_scan)
-               for (i = 0; i < ORINOCO_MAX_BSS_COUNT; i++)
-                       list_add_tail(&(PRIV_XBSS[i].list),
-                                     &priv->bss_free_list);
-       else
-               for (i = 0; i < ORINOCO_MAX_BSS_COUNT; i++)
-                       list_add_tail(&(PRIV_BSS[i].list),
-                                     &priv->bss_free_list);
-
-}
-
-void orinoco_clear_scan_results(struct orinoco_private *priv,
-                               unsigned long scan_age)
-{
-       if (priv->has_ext_scan) {
-               struct xbss_element *bss;
-               struct xbss_element *tmp_bss;
-
-               /* Blow away current list of scan results */
-               list_for_each_entry_safe(bss, tmp_bss, &priv->bss_list, list) {
-                       if (!scan_age ||
-                           time_after(jiffies, bss->last_scanned + scan_age)) {
-                               list_move_tail(&bss->list,
-                                              &priv->bss_free_list);
-                               /* Don't blow away ->list, just BSS data */
-                               memset(&bss->bss, 0, sizeof(bss->bss));
-                               bss->last_scanned = 0;
-                       }
-               }
-       } else {
-               struct bss_element *bss;
-               struct bss_element *tmp_bss;
-
-               /* Blow away current list of scan results */
-               list_for_each_entry_safe(bss, tmp_bss, &priv->bss_list, list) {
-                       if (!scan_age ||
-                           time_after(jiffies, bss->last_scanned + scan_age)) {
-                               list_move_tail(&bss->list,
-                                              &priv->bss_free_list);
-                               /* Don't blow away ->list, just BSS data */
-                               memset(&bss->bss, 0, sizeof(bss->bss));
-                               bss->last_scanned = 0;
-                       }
+       buf[0] = WLAN_EID_SUPP_RATES;
+       for (i = 0; i < 8; i++) {
+               /* NULL terminated */
+               if (rates[i] == 0x0)
+                       break;
+               buf[i + 2] = rates[i];
+       }
+       buf[1] = i;
+
+       /* We might still have another 2 rates, which need to go in
+        * extended supported rates */
+       if (i == 8 && rates[i] > 0) {
+               buf[10] = WLAN_EID_EXT_SUPP_RATES;
+               for (; i < 10; i++) {
+                       /* NULL terminated */
+                       if (rates[i] == 0x0)
+                               break;
+                       buf[i + 2] = rates[i];
                }
+               buf[11] = i - 8;
        }
+
+       return (i < 8) ? i + 2 : i + 4;
 }
 
-void orinoco_add_ext_scan_result(struct orinoco_private *priv,
-                                struct agere_ext_scan_info *atom)
+static void orinoco_add_hostscan_result(struct orinoco_private *priv,
+                                       const union hermes_scan_info *bss)
 {
-       struct xbss_element *bss = NULL;
-       int found = 0;
-
-       /* Try to update an existing bss first */
-       list_for_each_entry(bss, &priv->bss_list, list) {
-               if (compare_ether_addr(bss->bss.bssid, atom->bssid))
-                       continue;
-               /* ESSID lengths */
-               if (bss->bss.data[1] != atom->data[1])
-                       continue;
-               if (memcmp(&bss->bss.data[2], &atom->data[2],
-                          atom->data[1]))
-                       continue;
-               found = 1;
+       struct wiphy *wiphy = priv_to_wiphy(priv);
+       struct ieee80211_channel *channel;
+       u8 *ie;
+       u8 ie_buf[46];
+       u64 timestamp;
+       s32 signal;
+       u16 capability;
+       u16 beacon_interval;
+       int ie_len;
+       int freq;
+       int len;
+
+       len = le16_to_cpu(bss->a.essid_len);
+
+       /* Reconstruct SSID and bitrate IEs to pass up */
+       ie_buf[0] = WLAN_EID_SSID;
+       ie_buf[1] = len;
+       memcpy(&ie_buf[2], bss->a.essid, len);
+
+       ie = ie_buf + len + 2;
+       ie_len = ie_buf[1] + 2;
+       switch (priv->firmware_type) {
+       case FIRMWARE_TYPE_SYMBOL:
+               ie_len += symbol_build_supp_rates(ie, bss->s.rates);
                break;
-       }
 
-       /* Grab a bss off the free list */
-       if (!found && !list_empty(&priv->bss_free_list)) {
-               bss = list_entry(priv->bss_free_list.next,
-                                struct xbss_element, list);
-               list_del(priv->bss_free_list.next);
+       case FIRMWARE_TYPE_INTERSIL:
+               ie_len += prism_build_supp_rates(ie, bss->p.rates);
+               break;
 
-               list_add_tail(&bss->list, &priv->bss_list);
+       case FIRMWARE_TYPE_AGERE:
+       default:
+               break;
        }
 
-       if (bss) {
-               /* Always update the BSS to get latest beacon info */
-               memcpy(&bss->bss, atom, sizeof(bss->bss));
-               bss->last_scanned = jiffies;
-       }
+       freq = ieee80211_dsss_chan_to_freq(le16_to_cpu(bss->a.channel));
+       channel = ieee80211_get_channel(wiphy, freq);
+       timestamp = 0;
+       capability = le16_to_cpu(bss->a.capabilities);
+       beacon_interval = le16_to_cpu(bss->a.beacon_interv);
+       signal = SIGNAL_TO_MBM(le16_to_cpu(bss->a.level));
+
+       cfg80211_inform_bss(wiphy, channel, bss->a.bssid, timestamp,
+                           capability, beacon_interval, ie_buf, ie_len,
+                           signal, GFP_KERNEL);
 }
 
-int orinoco_process_scan_results(struct orinoco_private *priv,
-                                unsigned char *buf,
-                                int len)
+void orinoco_add_extscan_result(struct orinoco_private *priv,
+                               struct agere_ext_scan_info *bss,
+                               size_t len)
 {
-       int                     offset;         /* In the scan data */
-       union hermes_scan_info *atom;
-       int                     atom_len;
+       struct wiphy *wiphy = priv_to_wiphy(priv);
+       struct ieee80211_channel *channel;
+       u8 *ie;
+       u64 timestamp;
+       s32 signal;
+       u16 capability;
+       u16 beacon_interval;
+       size_t ie_len;
+       int chan, freq;
+
+       ie_len = len - sizeof(*bss);
+       ie = orinoco_get_ie(bss->data, ie_len, WLAN_EID_DS_PARAMS);
+       chan = ie ? ie[2] : 0;
+       freq = ieee80211_dsss_chan_to_freq(chan);
+       channel = ieee80211_get_channel(wiphy, freq);
+
+       timestamp = le64_to_cpu(bss->timestamp);
+       capability = le16_to_cpu(bss->capabilities);
+       beacon_interval = le16_to_cpu(bss->beacon_interval);
+       ie = bss->data;
+       signal = SIGNAL_TO_MBM(bss->level);
+
+       cfg80211_inform_bss(wiphy, channel, bss->bssid, timestamp,
+                           capability, beacon_interval, ie, ie_len,
+                           signal, GFP_KERNEL);
+}
+
+void orinoco_add_hostscan_results(struct orinoco_private *priv,
+                                 unsigned char *buf,
+                                 size_t len)
+{
+       int offset;             /* In the scan data */
+       size_t atom_len;
+       bool abort = false;
 
        switch (priv->firmware_type) {
        case FIRMWARE_TYPE_AGERE:
                atom_len = sizeof(struct agere_scan_apinfo);
                offset = 0;
                break;
+
        case FIRMWARE_TYPE_SYMBOL:
                /* Lack of documentation necessitates this hack.
                 * Different firmwares have 68 or 76 byte long atoms.
@@ -163,6 +182,7 @@ int orinoco_process_scan_results(struct orinoco_private *priv,
                        atom_len = 68;
                offset = 0;
                break;
+
        case FIRMWARE_TYPE_INTERSIL:
                offset = 4;
                if (priv->has_hostscan) {
@@ -170,64 +190,41 @@ int orinoco_process_scan_results(struct orinoco_private *priv,
                        /* Sanity check for atom_len */
                        if (atom_len < sizeof(struct prism2_scan_apinfo)) {
                                printk(KERN_ERR "%s: Invalid atom_len in scan "
-                                      "data: %d\n", priv->ndev->name,
+                                      "data: %zu\n", priv->ndev->name,
                                       atom_len);
-                               return -EIO;
+                               abort = true;
+                               goto scan_abort;
                        }
                } else
                        atom_len = offsetof(struct prism2_scan_apinfo, atim);
                break;
+
        default:
-               return -EOPNOTSUPP;
+               abort = true;
+               goto scan_abort;
        }
 
        /* Check that we got an whole number of atoms */
        if ((len - offset) % atom_len) {
-               printk(KERN_ERR "%s: Unexpected scan data length %d, "
-                      "atom_len %d, offset %d\n", priv->ndev->name, len,
+               printk(KERN_ERR "%s: Unexpected scan data length %zu, "
+                      "atom_len %zu, offset %d\n", priv->ndev->name, len,
                       atom_len, offset);
-               return -EIO;
+               abort = true;
+               goto scan_abort;
        }
 
-       orinoco_clear_scan_results(priv, msecs_to_jiffies(15000));
-
-       /* Read the entries one by one */
+       /* Process the entries one by one */
        for (; offset + atom_len <= len; offset += atom_len) {
-               int found = 0;
-               struct bss_element *bss = NULL;
+               union hermes_scan_info *atom;
 
-               /* Get next atom */
                atom = (union hermes_scan_info *) (buf + offset);
 
-               /* Try to update an existing bss first */
-               list_for_each_entry(bss, &priv->bss_list, list) {
-                       if (compare_ether_addr(bss->bss.a.bssid, atom->a.bssid))
-                               continue;
-                       if (le16_to_cpu(bss->bss.a.essid_len) !=
-                             le16_to_cpu(atom->a.essid_len))
-                               continue;
-                       if (memcmp(bss->bss.a.essid, atom->a.essid,
-                             le16_to_cpu(atom->a.essid_len)))
-                               continue;
-                       found = 1;
-                       break;
-               }
-
-               /* Grab a bss off the free list */
-               if (!found && !list_empty(&priv->bss_free_list)) {
-                       bss = list_entry(priv->bss_free_list.next,
-                                        struct bss_element, list);
-                       list_del(priv->bss_free_list.next);
-
-                       list_add_tail(&bss->list, &priv->bss_list);
-               }
-
-               if (bss) {
-                       /* Always update the BSS to get latest beacon info */
-                       memcpy(&bss->bss, atom, sizeof(bss->bss));
-                       bss->last_scanned = jiffies;
-               }
+               orinoco_add_hostscan_result(priv, atom);
        }
 
-       return 0;
+ scan_abort:
+       if (priv->scan_request) {
+               cfg80211_scan_done(priv->scan_request, abort);
+               priv->scan_request = NULL;
+       }
 }
index f319f74..2dc4e04 100644 (file)
@@ -9,21 +9,12 @@
 struct orinoco_private;
 struct agere_ext_scan_info;
 
-/* Setup and free memory for scan results */
-int orinoco_bss_data_allocate(struct orinoco_private *priv);
-void orinoco_bss_data_free(struct orinoco_private *priv);
-void orinoco_bss_data_init(struct orinoco_private *priv);
-
 /* Add scan results */
-void orinoco_add_ext_scan_result(struct orinoco_private *priv,
-                                struct agere_ext_scan_info *atom);
-int orinoco_process_scan_results(struct orinoco_private *dev,
-                                unsigned char *buf,
-                                int len);
-
-/* Clear scan results */
-void orinoco_clear_scan_results(struct orinoco_private *priv,
-                               unsigned long scan_age);
-
+void orinoco_add_extscan_result(struct orinoco_private *priv,
+                               struct agere_ext_scan_info *atom,
+                               size_t len);
+void orinoco_add_hostscan_results(struct orinoco_private *dev,
+                                 unsigned char *buf,
+                                 size_t len);
 
 #endif /* _ORINOCO_SCAN_H_ */
index 38e5198..c361310 100644 (file)
@@ -178,27 +178,25 @@ spectrum_cs_stop_firmware(struct orinoco_private *priv, int idle)
 static int
 spectrum_cs_probe(struct pcmcia_device *link)
 {
-       struct net_device *dev;
        struct orinoco_private *priv;
        struct orinoco_pccard *card;
 
-       dev = alloc_orinocodev(sizeof(*card), &handle_to_dev(link),
-                              spectrum_cs_hard_reset,
-                              spectrum_cs_stop_firmware);
-       if (!dev)
+       priv = alloc_orinocodev(sizeof(*card), &handle_to_dev(link),
+                               spectrum_cs_hard_reset,
+                               spectrum_cs_stop_firmware);
+       if (!priv)
                return -ENOMEM;
-       priv = netdev_priv(dev);
        card = priv->card;
 
        /* Link both structures together */
        card->p_dev = link;
-       link->priv = dev;
+       link->priv = priv;
 
        /* Interrupt setup */
        link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING | IRQ_HANDLE_PRESENT;
        link->irq.IRQInfo1 = IRQ_LEVEL_ID;
        link->irq.Handler = orinoco_interrupt;
-       link->irq.Instance = dev;
+       link->irq.Instance = priv;
 
        /* General socket configuration defaults can go here.  In this
         * client, we assume very little, and rely on the CIS for
@@ -219,14 +217,14 @@ spectrum_cs_probe(struct pcmcia_device *link)
  */
 static void spectrum_cs_detach(struct pcmcia_device *link)
 {
-       struct net_device *dev = link->priv;
+       struct orinoco_private *priv = link->priv;
 
        if (link->dev_node)
-               unregister_netdev(dev);
+               orinoco_if_del(priv);
 
        spectrum_cs_release(link);
 
-       free_orinocodev(dev);
+       free_orinocodev(priv);
 }                              /* spectrum_cs_detach */
 
 /*
@@ -306,8 +304,7 @@ next_entry:
 static int
 spectrum_cs_config(struct pcmcia_device *link)
 {
-       struct net_device *dev = link->priv;
-       struct orinoco_private *priv = netdev_priv(dev);
+       struct orinoco_private *priv = link->priv;
        struct orinoco_pccard *card = priv->card;
        hermes_t *hw = &priv->hw;
        int last_fn, last_ret;
@@ -362,34 +359,31 @@ spectrum_cs_config(struct pcmcia_device *link)
                 pcmcia_request_configuration(link, &link->conf));
 
        /* Ok, we have the configuration, prepare to register the netdev */
-       dev->base_addr = link->io.BasePort1;
-       dev->irq = link->irq.AssignedIRQ;
        card->node.major = card->node.minor = 0;
 
        /* Reset card */
        if (spectrum_cs_hard_reset(priv) != 0)
                goto failed;
 
-       SET_NETDEV_DEV(dev, &handle_to_dev(link));
-       /* Tell the stack we exist */
-       if (register_netdev(dev) != 0) {
-               printk(KERN_ERR PFX "register_netdev() failed\n");
+       /* Initialise the main driver */
+       if (orinoco_init(priv) != 0) {
+               printk(KERN_ERR PFX "orinoco_init() failed\n");
+               goto failed;
+       }
+
+       /* Register an interface with the stack */
+       if (orinoco_if_add(priv, link->io.BasePort1,
+                          link->irq.AssignedIRQ) != 0) {
+               printk(KERN_ERR PFX "orinoco_if_add() failed\n");
                goto failed;
        }
 
        /* At this point, the dev_node_t structure(s) needs to be
         * initialized and arranged in a linked list at link->dev_node. */
-       strcpy(card->node.dev_name, dev->name);
+       strcpy(card->node.dev_name, priv->ndev->name);
        link->dev_node = &card->node; /* link->dev_node being non-NULL is also
                                       * used to indicate that the
                                       * net_device has been registered */
-
-       /* Finally, report what we've done */
-       printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s, irq %d, io "
-              "0x%04x-0x%04x\n", dev->name, dev_name(dev->dev.parent),
-              link->irq.AssignedIRQ, link->io.BasePort1,
-              link->io.BasePort1 + link->io.NumPorts1 - 1);
-
        return 0;
 
  cs_failed:
@@ -408,8 +402,7 @@ spectrum_cs_config(struct pcmcia_device *link)
 static void
 spectrum_cs_release(struct pcmcia_device *link)
 {
-       struct net_device *dev = link->priv;
-       struct orinoco_private *priv = netdev_priv(dev);
+       struct orinoco_private *priv = link->priv;
        unsigned long flags;
 
        /* We're committed to taking the device away now, so mark the
@@ -427,23 +420,11 @@ spectrum_cs_release(struct pcmcia_device *link)
 static int
 spectrum_cs_suspend(struct pcmcia_device *link)
 {
-       struct net_device *dev = link->priv;
-       struct orinoco_private *priv = netdev_priv(dev);
-       unsigned long flags;
+       struct orinoco_private *priv = link->priv;
        int err = 0;
 
        /* Mark the device as stopped, to block IO until later */
-       spin_lock_irqsave(&priv->lock, flags);
-
-       err = __orinoco_down(dev);
-       if (err)
-               printk(KERN_WARNING "%s: Error %d downing interface\n",
-                      dev->name, err);
-
-       netif_device_detach(dev);
-       priv->hw_unavailable++;
-
-       spin_unlock_irqrestore(&priv->lock, flags);
+       orinoco_down(priv);
 
        return err;
 }
@@ -451,33 +432,10 @@ spectrum_cs_suspend(struct pcmcia_device *link)
 static int
 spectrum_cs_resume(struct pcmcia_device *link)
 {
-       struct net_device *dev = link->priv;
-       struct orinoco_private *priv = netdev_priv(dev);
-       unsigned long flags;
-       int err;
-
-       err = orinoco_reinit_firmware(dev);
-       if (err) {
-               printk(KERN_ERR "%s: Error %d re-initializing firmware\n",
-                      dev->name, err);
-               return -EIO;
-       }
-
-       spin_lock_irqsave(&priv->lock, flags);
-
-       netif_device_attach(dev);
-       priv->hw_unavailable--;
+       struct orinoco_private *priv = link->priv;
+       int err = orinoco_up(priv);
 
-       if (priv->open && !priv->hw_unavailable) {
-               err = __orinoco_up(dev);
-               if (err)
-                       printk(KERN_ERR "%s: Error %d restarting card\n",
-                              dev->name, err);
-       }
-
-       spin_unlock_irqrestore(&priv->lock, flags);
-
-       return 0;
+       return err;
 }
 
 
index 3f08142..b6ff3db 100644 (file)
@@ -7,6 +7,7 @@
 #include <linux/wireless.h>
 #include <linux/ieee80211.h>
 #include <net/iw_handler.h>
+#include <net/cfg80211.h>
 
 #include "hermes.h"
 #include "hermes_rid.h"
@@ -23,7 +24,7 @@
 
 static struct iw_statistics *orinoco_get_wireless_stats(struct net_device *dev)
 {
-       struct orinoco_private *priv = netdev_priv(dev);
+       struct orinoco_private *priv = ndev_priv(dev);
        hermes_t *hw = &priv->hw;
        struct iw_statistics *wstats = &priv->wstats;
        int err;
@@ -51,7 +52,7 @@ static struct iw_statistics *orinoco_get_wireless_stats(struct net_device *dev)
         * here so we're not safe to sleep here. */
        hermes_inquire(hw, HERMES_INQ_TALLIES);
 
-       if (priv->iw_mode == IW_MODE_ADHOC) {
+       if (priv->iw_mode == NL80211_IFTYPE_ADHOC) {
                memset(&wstats->qual, 0, sizeof(wstats->qual));
                /* If a spy address is defined, we report stats of the
                 * first spy address - Jean II */
@@ -87,31 +88,12 @@ static struct iw_statistics *orinoco_get_wireless_stats(struct net_device *dev)
 /* Wireless extensions                                              */
 /********************************************************************/
 
-static int orinoco_ioctl_getname(struct net_device *dev,
-                                struct iw_request_info *info,
-                                char *name,
-                                char *extra)
-{
-       struct orinoco_private *priv = netdev_priv(dev);
-       int numrates;
-       int err;
-
-       err = orinoco_hw_get_bitratelist(priv, &numrates, NULL, 0);
-
-       if (!err && (numrates > 2))
-               strcpy(name, "IEEE 802.11b");
-       else
-               strcpy(name, "IEEE 802.11-DS");
-
-       return 0;
-}
-
 static int orinoco_ioctl_setwap(struct net_device *dev,
                                struct iw_request_info *info,
                                struct sockaddr *ap_addr,
                                char *extra)
 {
-       struct orinoco_private *priv = netdev_priv(dev);
+       struct orinoco_private *priv = ndev_priv(dev);
        int err = -EINPROGRESS;         /* Call commit handler */
        unsigned long flags;
        static const u8 off_addr[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
@@ -142,7 +124,7 @@ static int orinoco_ioctl_setwap(struct net_device *dev,
                goto out;
        }
 
-       if (priv->iw_mode != IW_MODE_INFRA) {
+       if (priv->iw_mode != NL80211_IFTYPE_STATION) {
                printk(KERN_WARNING "%s: Manual roaming supported only in "
                       "managed mode\n", dev->name);
                err = -EOPNOTSUPP;
@@ -172,7 +154,7 @@ static int orinoco_ioctl_getwap(struct net_device *dev,
                                struct sockaddr *ap_addr,
                                char *extra)
 {
-       struct orinoco_private *priv = netdev_priv(dev);
+       struct orinoco_private *priv = ndev_priv(dev);
 
        hermes_t *hw = &priv->hw;
        int err = 0;
@@ -190,184 +172,12 @@ static int orinoco_ioctl_getwap(struct net_device *dev,
        return err;
 }
 
-static int orinoco_ioctl_setmode(struct net_device *dev,
-                                struct iw_request_info *info,
-                                u32 *mode,
-                                char *extra)
-{
-       struct orinoco_private *priv = netdev_priv(dev);
-       int err = -EINPROGRESS;         /* Call commit handler */
-       unsigned long flags;
-
-       if (priv->iw_mode == *mode)
-               return 0;
-
-       if (orinoco_lock(priv, &flags) != 0)
-               return -EBUSY;
-
-       switch (*mode) {
-       case IW_MODE_ADHOC:
-               if (!priv->has_ibss && !priv->has_port3)
-                       err = -EOPNOTSUPP;
-               break;
-
-       case IW_MODE_INFRA:
-               break;
-
-       case IW_MODE_MONITOR:
-               if (priv->broken_monitor && !force_monitor) {
-                       printk(KERN_WARNING "%s: Monitor mode support is "
-                              "buggy in this firmware, not enabling\n",
-                              dev->name);
-                       err = -EOPNOTSUPP;
-               }
-               break;
-
-       default:
-               err = -EOPNOTSUPP;
-               break;
-       }
-
-       if (err == -EINPROGRESS) {
-               priv->iw_mode = *mode;
-               set_port_type(priv);
-       }
-
-       orinoco_unlock(priv, &flags);
-
-       return err;
-}
-
-static int orinoco_ioctl_getmode(struct net_device *dev,
-                                struct iw_request_info *info,
-                                u32 *mode,
-                                char *extra)
-{
-       struct orinoco_private *priv = netdev_priv(dev);
-
-       *mode = priv->iw_mode;
-       return 0;
-}
-
-static int orinoco_ioctl_getiwrange(struct net_device *dev,
-                                   struct iw_request_info *info,
-                                   struct iw_point *rrq,
-                                   char *extra)
-{
-       struct orinoco_private *priv = netdev_priv(dev);
-       int err = 0;
-       struct iw_range *range = (struct iw_range *) extra;
-       int numrates;
-       int i, k;
-
-       rrq->length = sizeof(struct iw_range);
-       memset(range, 0, sizeof(struct iw_range));
-
-       range->we_version_compiled = WIRELESS_EXT;
-       range->we_version_source = 22;
-
-       /* Set available channels/frequencies */
-       range->num_channels = NUM_CHANNELS;
-       k = 0;
-       for (i = 0; i < NUM_CHANNELS; i++) {
-               if (priv->channel_mask & (1 << i)) {
-                       range->freq[k].i = i + 1;
-                       range->freq[k].m = (ieee80211_dsss_chan_to_freq(i + 1) *
-                                           100000);
-                       range->freq[k].e = 1;
-                       k++;
-               }
-
-               if (k >= IW_MAX_FREQUENCIES)
-                       break;
-       }
-       range->num_frequency = k;
-       range->sensitivity = 3;
-
-       if (priv->has_wep) {
-               range->max_encoding_tokens = ORINOCO_MAX_KEYS;
-               range->encoding_size[0] = SMALL_KEY_SIZE;
-               range->num_encoding_sizes = 1;
-
-               if (priv->has_big_wep) {
-                       range->encoding_size[1] = LARGE_KEY_SIZE;
-                       range->num_encoding_sizes = 2;
-               }
-       }
-
-       if (priv->has_wpa)
-               range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_CIPHER_TKIP;
-
-       if ((priv->iw_mode == IW_MODE_ADHOC) && (!SPY_NUMBER(priv))) {
-               /* Quality stats meaningless in ad-hoc mode */
-       } else {
-               range->max_qual.qual = 0x8b - 0x2f;
-               range->max_qual.level = 0x2f - 0x95 - 1;
-               range->max_qual.noise = 0x2f - 0x95 - 1;
-               /* Need to get better values */
-               range->avg_qual.qual = 0x24;
-               range->avg_qual.level = 0xC2;
-               range->avg_qual.noise = 0x9E;
-       }
-
-       err = orinoco_hw_get_bitratelist(priv, &numrates,
-                                        range->bitrate, IW_MAX_BITRATES);
-       if (err)
-               return err;
-       range->num_bitrates = numrates;
-
-       /* Set an indication of the max TCP throughput in bit/s that we can
-        * expect using this interface. May be use for QoS stuff...
-        * Jean II */
-       if (numrates > 2)
-               range->throughput = 5 * 1000 * 1000;    /* ~5 Mb/s */
-       else
-               range->throughput = 1.5 * 1000 * 1000;  /* ~1.5 Mb/s */
-
-       range->min_rts = 0;
-       range->max_rts = 2347;
-       range->min_frag = 256;
-       range->max_frag = 2346;
-
-       range->min_pmp = 0;
-       range->max_pmp = 65535000;
-       range->min_pmt = 0;
-       range->max_pmt = 65535 * 1000;  /* ??? */
-       range->pmp_flags = IW_POWER_PERIOD;
-       range->pmt_flags = IW_POWER_TIMEOUT;
-       range->pm_capa = (IW_POWER_PERIOD | IW_POWER_TIMEOUT |
-                         IW_POWER_UNICAST_R);
-
-       range->retry_capa = IW_RETRY_LIMIT | IW_RETRY_LIFETIME;
-       range->retry_flags = IW_RETRY_LIMIT;
-       range->r_time_flags = IW_RETRY_LIFETIME;
-       range->min_retry = 0;
-       range->max_retry = 65535;       /* ??? */
-       range->min_r_time = 0;
-       range->max_r_time = 65535 * 1000;       /* ??? */
-
-       if (priv->firmware_type == FIRMWARE_TYPE_AGERE)
-               range->scan_capa = IW_SCAN_CAPA_ESSID;
-       else
-               range->scan_capa = IW_SCAN_CAPA_NONE;
-
-       /* Event capability (kernel) */
-       IW_EVENT_CAPA_SET_KERNEL(range->event_capa);
-       /* Event capability (driver) */
-       IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWTHRSPY);
-       IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWAP);
-       IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWSCAN);
-       IW_EVENT_CAPA_SET(range->event_capa, IWEVTXDROP);
-
-       return 0;
-}
-
 static int orinoco_ioctl_setiwencode(struct net_device *dev,
                                     struct iw_request_info *info,
                                     struct iw_point *erq,
                                     char *keybuf)
 {
-       struct orinoco_private *priv = netdev_priv(dev);
+       struct orinoco_private *priv = ndev_priv(dev);
        int index = (erq->flags & IW_ENCODE_INDEX) - 1;
        int setindex = priv->tx_key;
        int encode_alg = priv->encode_alg;
@@ -469,7 +279,7 @@ static int orinoco_ioctl_getiwencode(struct net_device *dev,
                                     struct iw_point *erq,
                                     char *keybuf)
 {
-       struct orinoco_private *priv = netdev_priv(dev);
+       struct orinoco_private *priv = ndev_priv(dev);
        int index = (erq->flags & IW_ENCODE_INDEX) - 1;
        u16 xlen = 0;
        unsigned long flags;
@@ -508,7 +318,7 @@ static int orinoco_ioctl_setessid(struct net_device *dev,
                                  struct iw_point *erq,
                                  char *essidbuf)
 {
-       struct orinoco_private *priv = netdev_priv(dev);
+       struct orinoco_private *priv = ndev_priv(dev);
        unsigned long flags;
 
        /* Note : ESSID is ignored in Ad-Hoc demo mode, but we can set it
@@ -539,7 +349,7 @@ static int orinoco_ioctl_getessid(struct net_device *dev,
                                  struct iw_point *erq,
                                  char *essidbuf)
 {
-       struct orinoco_private *priv = netdev_priv(dev);
+       struct orinoco_private *priv = ndev_priv(dev);
        int active;
        int err = 0;
        unsigned long flags;
@@ -562,59 +372,18 @@ static int orinoco_ioctl_getessid(struct net_device *dev,
        return 0;
 }
 
-static int orinoco_ioctl_setnick(struct net_device *dev,
-                                struct iw_request_info *info,
-                                struct iw_point *nrq,
-                                char *nickbuf)
-{
-       struct orinoco_private *priv = netdev_priv(dev);
-       unsigned long flags;
-
-       if (nrq->length > IW_ESSID_MAX_SIZE)
-               return -E2BIG;
-
-       if (orinoco_lock(priv, &flags) != 0)
-               return -EBUSY;
-
-       memset(priv->nick, 0, sizeof(priv->nick));
-       memcpy(priv->nick, nickbuf, nrq->length);
-
-       orinoco_unlock(priv, &flags);
-
-       return -EINPROGRESS;            /* Call commit handler */
-}
-
-static int orinoco_ioctl_getnick(struct net_device *dev,
-                                struct iw_request_info *info,
-                                struct iw_point *nrq,
-                                char *nickbuf)
-{
-       struct orinoco_private *priv = netdev_priv(dev);
-       unsigned long flags;
-
-       if (orinoco_lock(priv, &flags) != 0)
-               return -EBUSY;
-
-       memcpy(nickbuf, priv->nick, IW_ESSID_MAX_SIZE);
-       orinoco_unlock(priv, &flags);
-
-       nrq->length = strlen(priv->nick);
-
-       return 0;
-}
-
 static int orinoco_ioctl_setfreq(struct net_device *dev,
                                 struct iw_request_info *info,
                                 struct iw_freq *frq,
                                 char *extra)
 {
-       struct orinoco_private *priv = netdev_priv(dev);
+       struct orinoco_private *priv = ndev_priv(dev);
        int chan = -1;
        unsigned long flags;
        int err = -EINPROGRESS;         /* Call commit handler */
 
        /* In infrastructure mode the AP sets the channel */
-       if (priv->iw_mode == IW_MODE_INFRA)
+       if (priv->iw_mode == NL80211_IFTYPE_STATION)
                return -EBUSY;
 
        if ((frq->e == 0) && (frq->m <= 1000)) {
@@ -640,7 +409,7 @@ static int orinoco_ioctl_setfreq(struct net_device *dev,
                return -EBUSY;
 
        priv->channel = chan;
-       if (priv->iw_mode == IW_MODE_MONITOR) {
+       if (priv->iw_mode == NL80211_IFTYPE_MONITOR) {
                /* Fast channel change - no commit if successful */
                hermes_t *hw = &priv->hw;
                err = hermes_docmd_wait(hw, HERMES_CMD_TEST |
@@ -657,7 +426,7 @@ static int orinoco_ioctl_getfreq(struct net_device *dev,
                                 struct iw_freq *frq,
                                 char *extra)
 {
-       struct orinoco_private *priv = netdev_priv(dev);
+       struct orinoco_private *priv = ndev_priv(dev);
        int tmp;
 
        /* Locking done in there */
@@ -676,7 +445,7 @@ static int orinoco_ioctl_getsens(struct net_device *dev,
                                 struct iw_param *srq,
                                 char *extra)
 {
-       struct orinoco_private *priv = netdev_priv(dev);
+       struct orinoco_private *priv = ndev_priv(dev);
        hermes_t *hw = &priv->hw;
        u16 val;
        int err;
@@ -705,7 +474,7 @@ static int orinoco_ioctl_setsens(struct net_device *dev,
                                 struct iw_param *srq,
                                 char *extra)
 {
-       struct orinoco_private *priv = netdev_priv(dev);
+       struct orinoco_private *priv = ndev_priv(dev);
        int val = srq->value;
        unsigned long flags;
 
@@ -728,7 +497,7 @@ static int orinoco_ioctl_setrts(struct net_device *dev,
                                struct iw_param *rrq,
                                char *extra)
 {
-       struct orinoco_private *priv = netdev_priv(dev);
+       struct orinoco_private *priv = ndev_priv(dev);
        int val = rrq->value;
        unsigned long flags;
 
@@ -752,7 +521,7 @@ static int orinoco_ioctl_getrts(struct net_device *dev,
                                struct iw_param *rrq,
                                char *extra)
 {
-       struct orinoco_private *priv = netdev_priv(dev);
+       struct orinoco_private *priv = ndev_priv(dev);
 
        rrq->value = priv->rts_thresh;
        rrq->disabled = (rrq->value == 2347);
@@ -766,7 +535,7 @@ static int orinoco_ioctl_setfrag(struct net_device *dev,
                                 struct iw_param *frq,
                                 char *extra)
 {
-       struct orinoco_private *priv = netdev_priv(dev);
+       struct orinoco_private *priv = ndev_priv(dev);
        int err = -EINPROGRESS;         /* Call commit handler */
        unsigned long flags;
 
@@ -806,7 +575,7 @@ static int orinoco_ioctl_getfrag(struct net_device *dev,
                                 struct iw_param *frq,
                                 char *extra)
 {
-       struct orinoco_private *priv = netdev_priv(dev);
+       struct orinoco_private *priv = ndev_priv(dev);
        hermes_t *hw = &priv->hw;
        int err;
        u16 val;
@@ -847,7 +616,7 @@ static int orinoco_ioctl_setrate(struct net_device *dev,
                                 struct iw_param *rrq,
                                 char *extra)
 {
-       struct orinoco_private *priv = netdev_priv(dev);
+       struct orinoco_private *priv = ndev_priv(dev);
        int ratemode;
        int bitrate; /* 100s of kilobits */
        unsigned long flags;
@@ -881,7 +650,7 @@ static int orinoco_ioctl_getrate(struct net_device *dev,
                                 struct iw_param *rrq,
                                 char *extra)
 {
-       struct orinoco_private *priv = netdev_priv(dev);
+       struct orinoco_private *priv = ndev_priv(dev);
        int err = 0;
        int bitrate, automatic;
        unsigned long flags;
@@ -910,7 +679,7 @@ static int orinoco_ioctl_setpower(struct net_device *dev,
                                  struct iw_param *prq,
                                  char *extra)
 {
-       struct orinoco_private *priv = netdev_priv(dev);
+       struct orinoco_private *priv = ndev_priv(dev);
        int err = -EINPROGRESS;         /* Call commit handler */
        unsigned long flags;
 
@@ -964,7 +733,7 @@ static int orinoco_ioctl_getpower(struct net_device *dev,
                                  struct iw_param *prq,
                                  char *extra)
 {
-       struct orinoco_private *priv = netdev_priv(dev);
+       struct orinoco_private *priv = ndev_priv(dev);
        hermes_t *hw = &priv->hw;
        int err = 0;
        u16 enable, period, timeout, mcast;
@@ -1018,7 +787,7 @@ static int orinoco_ioctl_set_encodeext(struct net_device *dev,
                                       union iwreq_data *wrqu,
                                       char *extra)
 {
-       struct orinoco_private *priv = netdev_priv(dev);
+       struct orinoco_private *priv = ndev_priv(dev);
        struct iw_point *encoding = &wrqu->encoding;
        struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
        int idx, alg = ext->alg, set_key = 1;
@@ -1079,7 +848,6 @@ static int orinoco_ioctl_set_encodeext(struct net_device *dev,
 
                case IW_ENCODE_ALG_TKIP:
                {
-                       hermes_t *hw = &priv->hw;
                        u8 *tkip_iv = NULL;
 
                        if (!priv->has_wpa ||
@@ -1094,7 +862,7 @@ static int orinoco_ioctl_set_encodeext(struct net_device *dev,
                        if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID)
                                tkip_iv = &ext->rx_seq[0];
 
-                       err = __orinoco_hw_set_tkip_key(hw, idx,
+                       err = __orinoco_hw_set_tkip_key(priv, idx,
                                 ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY,
                                 (u8 *) &priv->tkip_key[idx],
                                 tkip_iv, NULL);
@@ -1120,7 +888,7 @@ static int orinoco_ioctl_get_encodeext(struct net_device *dev,
                                       union iwreq_data *wrqu,
                                       char *extra)
 {
-       struct orinoco_private *priv = netdev_priv(dev);
+       struct orinoco_private *priv = ndev_priv(dev);
        struct iw_point *encoding = &wrqu->encoding;
        struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
        int idx, max_key_len;
@@ -1177,7 +945,7 @@ static int orinoco_ioctl_set_auth(struct net_device *dev,
                                  struct iw_request_info *info,
                                  union iwreq_data *wrqu, char *extra)
 {
-       struct orinoco_private *priv = netdev_priv(dev);
+       struct orinoco_private *priv = ndev_priv(dev);
        hermes_t *hw = &priv->hw;
        struct iw_param *param = &wrqu->param;
        unsigned long flags;
@@ -1255,7 +1023,7 @@ static int orinoco_ioctl_get_auth(struct net_device *dev,
                                  struct iw_request_info *info,
                                  union iwreq_data *wrqu, char *extra)
 {
-       struct orinoco_private *priv = netdev_priv(dev);
+       struct orinoco_private *priv = ndev_priv(dev);
        struct iw_param *param = &wrqu->param;
        unsigned long flags;
        int ret = 0;
@@ -1295,7 +1063,7 @@ static int orinoco_ioctl_set_genie(struct net_device *dev,
                                   struct iw_request_info *info,
                                   union iwreq_data *wrqu, char *extra)
 {
-       struct orinoco_private *priv = netdev_priv(dev);
+       struct orinoco_private *priv = ndev_priv(dev);
        u8 *buf;
        unsigned long flags;
 
@@ -1338,7 +1106,7 @@ static int orinoco_ioctl_get_genie(struct net_device *dev,
                                   struct iw_request_info *info,
                                   union iwreq_data *wrqu, char *extra)
 {
-       struct orinoco_private *priv = netdev_priv(dev);
+       struct orinoco_private *priv = ndev_priv(dev);
        unsigned long flags;
        int err = 0;
 
@@ -1367,7 +1135,7 @@ static int orinoco_ioctl_set_mlme(struct net_device *dev,
                                  struct iw_request_info *info,
                                  union iwreq_data *wrqu, char *extra)
 {
-       struct orinoco_private *priv = netdev_priv(dev);
+       struct orinoco_private *priv = ndev_priv(dev);
        hermes_t *hw = &priv->hw;
        struct iw_mlme *mlme = (struct iw_mlme *)extra;
        unsigned long flags;
@@ -1408,7 +1176,7 @@ static int orinoco_ioctl_getretry(struct net_device *dev,
                                  struct iw_param *rrq,
                                  char *extra)
 {
-       struct orinoco_private *priv = netdev_priv(dev);
+       struct orinoco_private *priv = ndev_priv(dev);
        hermes_t *hw = &priv->hw;
        int err = 0;
        u16 short_limit, long_limit, lifetime;
@@ -1462,7 +1230,7 @@ static int orinoco_ioctl_reset(struct net_device *dev,
                               void *wrqu,
                               char *extra)
 {
-       struct orinoco_private *priv = netdev_priv(dev);
+       struct orinoco_private *priv = ndev_priv(dev);
 
        if (!capable(CAP_NET_ADMIN))
                return -EPERM;
@@ -1487,7 +1255,7 @@ static int orinoco_ioctl_setibssport(struct net_device *dev,
                                     char *extra)
 
 {
-       struct orinoco_private *priv = netdev_priv(dev);
+       struct orinoco_private *priv = ndev_priv(dev);
        int val = *((int *) extra);
        unsigned long flags;
 
@@ -1508,7 +1276,7 @@ static int orinoco_ioctl_getibssport(struct net_device *dev,
                                     void *wrqu,
                                     char *extra)
 {
-       struct orinoco_private *priv = netdev_priv(dev);
+       struct orinoco_private *priv = ndev_priv(dev);
        int *val = (int *) extra;
 
        *val = priv->ibss_port;
@@ -1520,7 +1288,7 @@ static int orinoco_ioctl_setport3(struct net_device *dev,
                                  void *wrqu,
                                  char *extra)
 {
-       struct orinoco_private *priv = netdev_priv(dev);
+       struct orinoco_private *priv = ndev_priv(dev);
        int val = *((int *) extra);
        int err = 0;
        unsigned long flags;
@@ -1566,7 +1334,7 @@ static int orinoco_ioctl_getport3(struct net_device *dev,
                                  void *wrqu,
                                  char *extra)
 {
-       struct orinoco_private *priv = netdev_priv(dev);
+       struct orinoco_private *priv = ndev_priv(dev);
        int *val = (int *) extra;
 
        *val = priv->prefer_port3;
@@ -1578,7 +1346,7 @@ static int orinoco_ioctl_setpreamble(struct net_device *dev,
                                     void *wrqu,
                                     char *extra)
 {
-       struct orinoco_private *priv = netdev_priv(dev);
+       struct orinoco_private *priv = ndev_priv(dev);
        unsigned long flags;
        int val;
 
@@ -1610,7 +1378,7 @@ static int orinoco_ioctl_getpreamble(struct net_device *dev,
                                     void *wrqu,
                                     char *extra)
 {
-       struct orinoco_private *priv = netdev_priv(dev);
+       struct orinoco_private *priv = ndev_priv(dev);
        int *val = (int *) extra;
 
        if (!priv->has_preamble)
@@ -1630,7 +1398,7 @@ static int orinoco_ioctl_getrid(struct net_device *dev,
                                struct iw_point *data,
                                char *extra)
 {
-       struct orinoco_private *priv = netdev_priv(dev);
+       struct orinoco_private *priv = ndev_priv(dev);
        hermes_t *hw = &priv->hw;
        int rid = data->flags;
        u16 length;
@@ -1661,519 +1429,6 @@ static int orinoco_ioctl_getrid(struct net_device *dev,
        return err;
 }
 
-/* Trigger a scan (look for other cells in the vicinity) */
-static int orinoco_ioctl_setscan(struct net_device *dev,
-                                struct iw_request_info *info,
-                                struct iw_point *srq,
-                                char *extra)
-{
-       struct orinoco_private *priv = netdev_priv(dev);
-       hermes_t *hw = &priv->hw;
-       struct iw_scan_req *si = (struct iw_scan_req *) extra;
-       int err = 0;
-       unsigned long flags;
-
-       /* Note : you may have realised that, as this is a SET operation,
-        * this is privileged and therefore a normal user can't
-        * perform scanning.
-        * This is not an error, while the device perform scanning,
-        * traffic doesn't flow, so it's a perfect DoS...
-        * Jean II */
-
-       if (orinoco_lock(priv, &flags) != 0)
-               return -EBUSY;
-
-       /* Scanning with port 0 disabled would fail */
-       if (!netif_running(dev)) {
-               err = -ENETDOWN;
-               goto out;
-       }
-
-       /* In monitor mode, the scan results are always empty.
-        * Probe responses are passed to the driver as received
-        * frames and could be processed in software. */
-       if (priv->iw_mode == IW_MODE_MONITOR) {
-               err = -EOPNOTSUPP;
-               goto out;
-       }
-
-       /* Note : because we don't lock out the irq handler, the way
-        * we access scan variables in priv is critical.
-        *      o scan_inprogress : not touched by irq handler
-        *      o scan_mode : not touched by irq handler
-        * Before modifying anything on those variables, please think hard !
-        * Jean II */
-
-       /* Save flags */
-       priv->scan_mode = srq->flags;
-
-       /* Always trigger scanning, even if it's in progress.
-        * This way, if the info frame get lost, we will recover somewhat
-        * gracefully  - Jean II */
-
-       if (priv->has_hostscan) {
-               switch (priv->firmware_type) {
-               case FIRMWARE_TYPE_SYMBOL:
-                       err = hermes_write_wordrec(hw, USER_BAP,
-                                               HERMES_RID_CNFHOSTSCAN_SYMBOL,
-                                               HERMES_HOSTSCAN_SYMBOL_ONCE |
-                                               HERMES_HOSTSCAN_SYMBOL_BCAST);
-                       break;
-               case FIRMWARE_TYPE_INTERSIL: {
-                       __le16 req[3];
-
-                       req[0] = cpu_to_le16(0x3fff);   /* All channels */
-                       req[1] = cpu_to_le16(0x0001);   /* rate 1 Mbps */
-                       req[2] = 0;                     /* Any ESSID */
-                       err = HERMES_WRITE_RECORD(hw, USER_BAP,
-                                                 HERMES_RID_CNFHOSTSCAN, &req);
-               }
-               break;
-               case FIRMWARE_TYPE_AGERE:
-                       if (priv->scan_mode & IW_SCAN_THIS_ESSID) {
-                               struct hermes_idstring idbuf;
-                               size_t len = min(sizeof(idbuf.val),
-                                                (size_t) si->essid_len);
-                               idbuf.len = cpu_to_le16(len);
-                               memcpy(idbuf.val, si->essid, len);
-
-                               err = hermes_write_ltv(hw, USER_BAP,
-                                              HERMES_RID_CNFSCANSSID_AGERE,
-                                              HERMES_BYTES_TO_RECLEN(len + 2),
-                                              &idbuf);
-                       } else
-                               err = hermes_write_wordrec(hw, USER_BAP,
-                                                  HERMES_RID_CNFSCANSSID_AGERE,
-                                                  0);  /* Any ESSID */
-                       if (err)
-                               break;
-
-                       if (priv->has_ext_scan) {
-                               /* Clear scan results at the start of
-                                * an extended scan */
-                               orinoco_clear_scan_results(priv,
-                                               msecs_to_jiffies(15000));
-
-                               /* TODO: Is this available on older firmware?
-                                *   Can we use it to scan specific channels
-                                *   for IW_SCAN_THIS_FREQ? */
-                               err = hermes_write_wordrec(hw, USER_BAP,
-                                               HERMES_RID_CNFSCANCHANNELS2GHZ,
-                                               0x7FFF);
-                               if (err)
-                                       goto out;
-
-                               err = hermes_inquire(hw,
-                                                    HERMES_INQ_CHANNELINFO);
-                       } else
-                               err = hermes_inquire(hw, HERMES_INQ_SCAN);
-                       break;
-               }
-       } else
-               err = hermes_inquire(hw, HERMES_INQ_SCAN);
-
-       /* One more client */
-       if (!err)
-               priv->scan_inprogress = 1;
-
- out:
-       orinoco_unlock(priv, &flags);
-       return err;
-}
-
-#define MAX_CUSTOM_LEN 64
-
-/* Translate scan data returned from the card to a card independant
- * format that the Wireless Tools will understand - Jean II */
-static inline char *orinoco_translate_scan(struct net_device *dev,
-                                          struct iw_request_info *info,
-                                          char *current_ev,
-                                          char *end_buf,
-                                          union hermes_scan_info *bss,
-                                          unsigned long last_scanned)
-{
-       struct orinoco_private *priv = netdev_priv(dev);
-       u16                     capabilities;
-       u16                     channel;
-       struct iw_event         iwe;            /* Temporary buffer */
-       char custom[MAX_CUSTOM_LEN];
-
-       memset(&iwe, 0, sizeof(iwe));
-
-       /* First entry *MUST* be the AP MAC address */
-       iwe.cmd = SIOCGIWAP;
-       iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
-       memcpy(iwe.u.ap_addr.sa_data, bss->a.bssid, ETH_ALEN);
-       current_ev = iwe_stream_add_event(info, current_ev, end_buf,
-                                         &iwe, IW_EV_ADDR_LEN);
-
-       /* Other entries will be displayed in the order we give them */
-
-       /* Add the ESSID */
-       iwe.u.data.length = le16_to_cpu(bss->a.essid_len);
-       if (iwe.u.data.length > 32)
-               iwe.u.data.length = 32;
-       iwe.cmd = SIOCGIWESSID;
-       iwe.u.data.flags = 1;
-       current_ev = iwe_stream_add_point(info, current_ev, end_buf,
-                                         &iwe, bss->a.essid);
-
-       /* Add mode */
-       iwe.cmd = SIOCGIWMODE;
-       capabilities = le16_to_cpu(bss->a.capabilities);
-       if (capabilities & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)) {
-               if (capabilities & WLAN_CAPABILITY_ESS)
-                       iwe.u.mode = IW_MODE_MASTER;
-               else
-                       iwe.u.mode = IW_MODE_ADHOC;
-               current_ev = iwe_stream_add_event(info, current_ev, end_buf,
-                                                 &iwe, IW_EV_UINT_LEN);
-       }
-
-       channel = bss->s.channel;
-       if ((channel >= 1) && (channel <= NUM_CHANNELS)) {
-               /* Add channel and frequency */
-               iwe.cmd = SIOCGIWFREQ;
-               iwe.u.freq.m = channel;
-               iwe.u.freq.e = 0;
-               current_ev = iwe_stream_add_event(info, current_ev, end_buf,
-                                                 &iwe, IW_EV_FREQ_LEN);
-
-               iwe.u.freq.m = ieee80211_dsss_chan_to_freq(channel) * 100000;
-               iwe.u.freq.e = 1;
-               current_ev = iwe_stream_add_event(info, current_ev, end_buf,
-                                                 &iwe, IW_EV_FREQ_LEN);
-       }
-
-       /* Add quality statistics. level and noise in dB. No link quality */
-       iwe.cmd = IWEVQUAL;
-       iwe.u.qual.updated = IW_QUAL_DBM | IW_QUAL_QUAL_INVALID;
-       iwe.u.qual.level = (__u8) le16_to_cpu(bss->a.level) - 0x95;
-       iwe.u.qual.noise = (__u8) le16_to_cpu(bss->a.noise) - 0x95;
-       /* Wireless tools prior to 27.pre22 will show link quality
-        * anyway, so we provide a reasonable value. */
-       if (iwe.u.qual.level > iwe.u.qual.noise)
-               iwe.u.qual.qual = iwe.u.qual.level - iwe.u.qual.noise;
-       else
-               iwe.u.qual.qual = 0;
-       current_ev = iwe_stream_add_event(info, current_ev, end_buf,
-                                         &iwe, IW_EV_QUAL_LEN);
-
-       /* Add encryption capability */
-       iwe.cmd = SIOCGIWENCODE;
-       if (capabilities & WLAN_CAPABILITY_PRIVACY)
-               iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
-       else
-               iwe.u.data.flags = IW_ENCODE_DISABLED;
-       iwe.u.data.length = 0;
-       current_ev = iwe_stream_add_point(info, current_ev, end_buf,
-                                         &iwe, NULL);
-
-       /* Bit rate is not available in Lucent/Agere firmwares */
-       if (priv->firmware_type != FIRMWARE_TYPE_AGERE) {
-               char *current_val = current_ev + iwe_stream_lcp_len(info);
-               int i;
-               int step;
-
-               if (priv->firmware_type == FIRMWARE_TYPE_SYMBOL)
-                       step = 2;
-               else
-                       step = 1;
-
-               iwe.cmd = SIOCGIWRATE;
-               /* Those two flags are ignored... */
-               iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
-               /* Max 10 values */
-               for (i = 0; i < 10; i += step) {
-                       /* NULL terminated */
-                       if (bss->p.rates[i] == 0x0)
-                               break;
-                       /* Bit rate given in 500 kb/s units (+ 0x80) */
-                       iwe.u.bitrate.value =
-                               ((bss->p.rates[i] & 0x7f) * 500000);
-                       current_val = iwe_stream_add_value(info, current_ev,
-                                                          current_val,
-                                                          end_buf, &iwe,
-                                                          IW_EV_PARAM_LEN);
-               }
-               /* Check if we added any event */
-               if ((current_val - current_ev) > iwe_stream_lcp_len(info))
-                       current_ev = current_val;
-       }
-
-       /* Beacon interval */
-       iwe.cmd = IWEVCUSTOM;
-       iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN,
-                                    "bcn_int=%d",
-                                    le16_to_cpu(bss->a.beacon_interv));
-       if (iwe.u.data.length)
-               current_ev = iwe_stream_add_point(info, current_ev, end_buf,
-                                                 &iwe, custom);
-
-       /* Capabilites */
-       iwe.cmd = IWEVCUSTOM;
-       iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN,
-                                    "capab=0x%04x",
-                                    capabilities);
-       if (iwe.u.data.length)
-               current_ev = iwe_stream_add_point(info, current_ev, end_buf,
-                                                 &iwe, custom);
-
-       /* Add EXTRA: Age to display seconds since last beacon/probe response
-        * for given network. */
-       iwe.cmd = IWEVCUSTOM;
-       iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN,
-                                    " Last beacon: %dms ago",
-                                    jiffies_to_msecs(jiffies - last_scanned));
-       if (iwe.u.data.length)
-               current_ev = iwe_stream_add_point(info, current_ev, end_buf,
-                                                 &iwe, custom);
-
-       return current_ev;
-}
-
-static inline char *orinoco_translate_ext_scan(struct net_device *dev,
-                                              struct iw_request_info *info,
-                                              char *current_ev,
-                                              char *end_buf,
-                                              struct agere_ext_scan_info *bss,
-                                              unsigned long last_scanned)
-{
-       u16                     capabilities;
-       u16                     channel;
-       struct iw_event         iwe;            /* Temporary buffer */
-       char custom[MAX_CUSTOM_LEN];
-       u8 *ie;
-
-       memset(&iwe, 0, sizeof(iwe));
-
-       /* First entry *MUST* be the AP MAC address */
-       iwe.cmd = SIOCGIWAP;
-       iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
-       memcpy(iwe.u.ap_addr.sa_data, bss->bssid, ETH_ALEN);
-       current_ev = iwe_stream_add_event(info, current_ev, end_buf,
-                                         &iwe, IW_EV_ADDR_LEN);
-
-       /* Other entries will be displayed in the order we give them */
-
-       /* Add the ESSID */
-       ie = bss->data;
-       iwe.u.data.length = ie[1];
-       if (iwe.u.data.length) {
-               if (iwe.u.data.length > 32)
-                       iwe.u.data.length = 32;
-               iwe.cmd = SIOCGIWESSID;
-               iwe.u.data.flags = 1;
-               current_ev = iwe_stream_add_point(info, current_ev, end_buf,
-                                                 &iwe, &ie[2]);
-       }
-
-       /* Add mode */
-       capabilities = le16_to_cpu(bss->capabilities);
-       if (capabilities & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)) {
-               iwe.cmd = SIOCGIWMODE;
-               if (capabilities & WLAN_CAPABILITY_ESS)
-                       iwe.u.mode = IW_MODE_MASTER;
-               else
-                       iwe.u.mode = IW_MODE_ADHOC;
-               current_ev = iwe_stream_add_event(info, current_ev, end_buf,
-                                                 &iwe, IW_EV_UINT_LEN);
-       }
-
-       ie = orinoco_get_ie(bss->data, sizeof(bss->data), WLAN_EID_DS_PARAMS);
-       channel = ie ? ie[2] : 0;
-       if ((channel >= 1) && (channel <= NUM_CHANNELS)) {
-               /* Add channel and frequency */
-               iwe.cmd = SIOCGIWFREQ;
-               iwe.u.freq.m = channel;
-               iwe.u.freq.e = 0;
-               current_ev = iwe_stream_add_event(info, current_ev, end_buf,
-                                                 &iwe, IW_EV_FREQ_LEN);
-
-               iwe.u.freq.m = ieee80211_dsss_chan_to_freq(channel) * 100000;
-               iwe.u.freq.e = 1;
-               current_ev = iwe_stream_add_event(info, current_ev, end_buf,
-                                                 &iwe, IW_EV_FREQ_LEN);
-       }
-
-       /* Add quality statistics. level and noise in dB. No link quality */
-       iwe.cmd = IWEVQUAL;
-       iwe.u.qual.updated = IW_QUAL_DBM | IW_QUAL_QUAL_INVALID;
-       iwe.u.qual.level = bss->level - 0x95;
-       iwe.u.qual.noise = bss->noise - 0x95;
-       /* Wireless tools prior to 27.pre22 will show link quality
-        * anyway, so we provide a reasonable value. */
-       if (iwe.u.qual.level > iwe.u.qual.noise)
-               iwe.u.qual.qual = iwe.u.qual.level - iwe.u.qual.noise;
-       else
-               iwe.u.qual.qual = 0;
-       current_ev = iwe_stream_add_event(info, current_ev, end_buf,
-                                         &iwe, IW_EV_QUAL_LEN);
-
-       /* Add encryption capability */
-       iwe.cmd = SIOCGIWENCODE;
-       if (capabilities & WLAN_CAPABILITY_PRIVACY)
-               iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
-       else
-               iwe.u.data.flags = IW_ENCODE_DISABLED;
-       iwe.u.data.length = 0;
-       current_ev = iwe_stream_add_point(info, current_ev, end_buf,
-                                         &iwe, NULL);
-
-       /* WPA IE */
-       ie = orinoco_get_wpa_ie(bss->data, sizeof(bss->data));
-       if (ie) {
-               iwe.cmd = IWEVGENIE;
-               iwe.u.data.length = ie[1] + 2;
-               current_ev = iwe_stream_add_point(info, current_ev, end_buf,
-                                                 &iwe, ie);
-       }
-
-       /* RSN IE */
-       ie = orinoco_get_ie(bss->data, sizeof(bss->data), WLAN_EID_RSN);
-       if (ie) {
-               iwe.cmd = IWEVGENIE;
-               iwe.u.data.length = ie[1] + 2;
-               current_ev = iwe_stream_add_point(info, current_ev, end_buf,
-                                                 &iwe, ie);
-       }
-
-       ie = orinoco_get_ie(bss->data, sizeof(bss->data), WLAN_EID_SUPP_RATES);
-       if (ie) {
-               char *p = current_ev + iwe_stream_lcp_len(info);
-               int i;
-
-               iwe.cmd = SIOCGIWRATE;
-               /* Those two flags are ignored... */
-               iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
-
-               for (i = 2; i < (ie[1] + 2); i++) {
-                       iwe.u.bitrate.value = ((ie[i] & 0x7F) * 500000);
-                       p = iwe_stream_add_value(info, current_ev, p, end_buf,
-                                                &iwe, IW_EV_PARAM_LEN);
-               }
-               /* Check if we added any event */
-               if (p > (current_ev + iwe_stream_lcp_len(info)))
-                       current_ev = p;
-       }
-
-       /* Timestamp */
-       iwe.cmd = IWEVCUSTOM;
-       iwe.u.data.length =
-               snprintf(custom, MAX_CUSTOM_LEN, "tsf=%016llx",
-                        (unsigned long long) le64_to_cpu(bss->timestamp));
-       if (iwe.u.data.length)
-               current_ev = iwe_stream_add_point(info, current_ev, end_buf,
-                                                 &iwe, custom);
-
-       /* Beacon interval */
-       iwe.cmd = IWEVCUSTOM;
-       iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN,
-                                    "bcn_int=%d",
-                                    le16_to_cpu(bss->beacon_interval));
-       if (iwe.u.data.length)
-               current_ev = iwe_stream_add_point(info, current_ev, end_buf,
-                                                 &iwe, custom);
-
-       /* Capabilites */
-       iwe.cmd = IWEVCUSTOM;
-       iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN,
-                                    "capab=0x%04x",
-                                    capabilities);
-       if (iwe.u.data.length)
-               current_ev = iwe_stream_add_point(info, current_ev, end_buf,
-                                                 &iwe, custom);
-
-       /* Add EXTRA: Age to display seconds since last beacon/probe response
-        * for given network. */
-       iwe.cmd = IWEVCUSTOM;
-       iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN,
-                                    " Last beacon: %dms ago",
-                                    jiffies_to_msecs(jiffies - last_scanned));
-       if (iwe.u.data.length)
-               current_ev = iwe_stream_add_point(info, current_ev, end_buf,
-                                                 &iwe, custom);
-
-       return current_ev;
-}
-
-/* Return results of a scan */
-static int orinoco_ioctl_getscan(struct net_device *dev,
-                                struct iw_request_info *info,
-                                struct iw_point *srq,
-                                char *extra)
-{
-       struct orinoco_private *priv = netdev_priv(dev);
-       int err = 0;
-       unsigned long flags;
-       char *current_ev = extra;
-
-       if (orinoco_lock(priv, &flags) != 0)
-               return -EBUSY;
-
-       if (priv->scan_inprogress) {
-               /* Important note : we don't want to block the caller
-                * until results are ready for various reasons.
-                * First, managing wait queues is complex and racy.
-                * Second, we grab some rtnetlink lock before comming
-                * here (in dev_ioctl()).
-                * Third, we generate an Wireless Event, so the
-                * caller can wait itself on that - Jean II */
-               err = -EAGAIN;
-               goto out;
-       }
-
-       if (priv->has_ext_scan) {
-               struct xbss_element *bss;
-
-               list_for_each_entry(bss, &priv->bss_list, list) {
-                       /* Translate this entry to WE format */
-                       current_ev =
-                               orinoco_translate_ext_scan(dev, info,
-                                                          current_ev,
-                                                          extra + srq->length,
-                                                          &bss->bss,
-                                                          bss->last_scanned);
-
-                       /* Check if there is space for one more entry */
-                       if ((extra + srq->length - current_ev)
-                           <= IW_EV_ADDR_LEN) {
-                               /* Ask user space to try again with a
-                                * bigger buffer */
-                               err = -E2BIG;
-                               goto out;
-                       }
-               }
-
-       } else {
-               struct bss_element *bss;
-
-               list_for_each_entry(bss, &priv->bss_list, list) {
-                       /* Translate this entry to WE format */
-                       current_ev = orinoco_translate_scan(dev, info,
-                                                           current_ev,
-                                                           extra + srq->length,
-                                                           &bss->bss,
-                                                           bss->last_scanned);
-
-                       /* Check if there is space for one more entry */
-                       if ((extra + srq->length - current_ev)
-                           <= IW_EV_ADDR_LEN) {
-                               /* Ask user space to try again with a
-                                * bigger buffer */
-                               err = -E2BIG;
-                               goto out;
-                       }
-               }
-       }
-
-       srq->length = (current_ev - extra);
-       srq->flags = (__u16) priv->scan_mode;
-
-out:
-       orinoco_unlock(priv, &flags);
-       return err;
-}
 
 /* Commit handler, called after set operations */
 static int orinoco_ioctl_commit(struct net_device *dev,
@@ -2181,50 +1436,17 @@ static int orinoco_ioctl_commit(struct net_device *dev,
                                void *wrqu,
                                char *extra)
 {
-       struct orinoco_private *priv = netdev_priv(dev);
-       struct hermes *hw = &priv->hw;
+       struct orinoco_private *priv = ndev_priv(dev);
        unsigned long flags;
        int err = 0;
 
        if (!priv->open)
                return 0;
 
-       if (priv->broken_disableport) {
-               orinoco_reset(&priv->reset_work);
-               return 0;
-       }
-
        if (orinoco_lock(priv, &flags) != 0)
                return err;
 
-       err = hermes_disable_port(hw, 0);
-       if (err) {
-               printk(KERN_WARNING "%s: Unable to disable port "
-                      "while reconfiguring card\n", dev->name);
-               priv->broken_disableport = 1;
-               goto out;
-       }
-
-       err = __orinoco_program_rids(dev);
-       if (err) {
-               printk(KERN_WARNING "%s: Unable to reconfigure card\n",
-                      dev->name);
-               goto out;
-       }
-
-       err = hermes_enable_port(hw, 0);
-       if (err) {
-               printk(KERN_WARNING "%s: Unable to enable port while reconfiguring card\n",
-                      dev->name);
-               goto out;
-       }
-
- out:
-       if (err) {
-               printk(KERN_WARNING "%s: Resetting instead...\n", dev->name);
-               schedule_work(&priv->reset_work);
-               err = 0;
-       }
+       err = orinoco_commit(priv);
 
        orinoco_unlock(priv, &flags);
        return err;
@@ -2258,26 +1480,24 @@ static const struct iw_priv_args orinoco_privtab[] = {
        [IW_IOCTL_IDX(id)] = (iw_handler) func
 static const iw_handler        orinoco_handler[] = {
        STD_IW_HANDLER(SIOCSIWCOMMIT,   orinoco_ioctl_commit),
-       STD_IW_HANDLER(SIOCGIWNAME,     orinoco_ioctl_getname),
+       STD_IW_HANDLER(SIOCGIWNAME,     cfg80211_wext_giwname),
        STD_IW_HANDLER(SIOCSIWFREQ,     orinoco_ioctl_setfreq),
        STD_IW_HANDLER(SIOCGIWFREQ,     orinoco_ioctl_getfreq),
-       STD_IW_HANDLER(SIOCSIWMODE,     orinoco_ioctl_setmode),
-       STD_IW_HANDLER(SIOCGIWMODE,     orinoco_ioctl_getmode),
+       STD_IW_HANDLER(SIOCSIWMODE,     cfg80211_wext_siwmode),
+       STD_IW_HANDLER(SIOCGIWMODE,     cfg80211_wext_giwmode),
        STD_IW_HANDLER(SIOCSIWSENS,     orinoco_ioctl_setsens),
        STD_IW_HANDLER(SIOCGIWSENS,     orinoco_ioctl_getsens),
-       STD_IW_HANDLER(SIOCGIWRANGE,    orinoco_ioctl_getiwrange),
+       STD_IW_HANDLER(SIOCGIWRANGE,    cfg80211_wext_giwrange),
        STD_IW_HANDLER(SIOCSIWSPY,      iw_handler_set_spy),
        STD_IW_HANDLER(SIOCGIWSPY,      iw_handler_get_spy),
        STD_IW_HANDLER(SIOCSIWTHRSPY,   iw_handler_set_thrspy),
        STD_IW_HANDLER(SIOCGIWTHRSPY,   iw_handler_get_thrspy),
        STD_IW_HANDLER(SIOCSIWAP,       orinoco_ioctl_setwap),
        STD_IW_HANDLER(SIOCGIWAP,       orinoco_ioctl_getwap),
-       STD_IW_HANDLER(SIOCSIWSCAN,     orinoco_ioctl_setscan),
-       STD_IW_HANDLER(SIOCGIWSCAN,     orinoco_ioctl_getscan),
+       STD_IW_HANDLER(SIOCSIWSCAN,     cfg80211_wext_siwscan),
+       STD_IW_HANDLER(SIOCGIWSCAN,     cfg80211_wext_giwscan),
        STD_IW_HANDLER(SIOCSIWESSID,    orinoco_ioctl_setessid),
        STD_IW_HANDLER(SIOCGIWESSID,    orinoco_ioctl_getessid),
-       STD_IW_HANDLER(SIOCSIWNICKN,    orinoco_ioctl_setnick),
-       STD_IW_HANDLER(SIOCGIWNICKN,    orinoco_ioctl_getnick),
        STD_IW_HANDLER(SIOCSIWRATE,     orinoco_ioctl_setrate),
        STD_IW_HANDLER(SIOCGIWRATE,     orinoco_ioctl_getrate),
        STD_IW_HANDLER(SIOCSIWRTS,      orinoco_ioctl_setrts),
index c2050de..b542e68 100644 (file)
@@ -1,3 +1,6 @@
+p54common-objs                 := eeprom.o fwio.o txrx.o main.o
+p54common-$(CONFIG_P54_LEDS)   += led.o
+
 obj-$(CONFIG_P54_COMMON)       += p54common.o
 obj-$(CONFIG_P54_USB)          += p54usb.o
 obj-$(CONFIG_P54_PCI)          += p54pci.o
diff --git a/drivers/net/wireless/p54/eeprom.c b/drivers/net/wireless/p54/eeprom.c
new file mode 100644 (file)
index 0000000..a2a044e
--- /dev/null
@@ -0,0 +1,564 @@
+/*
+ * EEPROM parser code for mac80211 Prism54 drivers
+ *
+ * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
+ * Copyright (c) 2007-2009, Christian Lamparter <chunkeey@web.de>
+ * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
+ *
+ * Based on:
+ * - the islsm (softmac prism54) driver, which is:
+ *   Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
+ * - stlc45xx driver
+ *   Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/firmware.h>
+#include <linux/etherdevice.h>
+
+#include <net/mac80211.h>
+
+#include "p54.h"
+#include "eeprom.h"
+#include "lmac.h"
+
+static struct ieee80211_rate p54_bgrates[] = {
+       { .bitrate = 10, .hw_value = 0, },
+       { .bitrate = 20, .hw_value = 1, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
+       { .bitrate = 55, .hw_value = 2, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
+       { .bitrate = 110, .hw_value = 3, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
+       { .bitrate = 60, .hw_value = 4, },
+       { .bitrate = 90, .hw_value = 5, },
+       { .bitrate = 120, .hw_value = 6, },
+       { .bitrate = 180, .hw_value = 7, },
+       { .bitrate = 240, .hw_value = 8, },
+       { .bitrate = 360, .hw_value = 9, },
+       { .bitrate = 480, .hw_value = 10, },
+       { .bitrate = 540, .hw_value = 11, },
+};
+
+static struct ieee80211_channel p54_bgchannels[] = {
+       { .center_freq = 2412, .hw_value = 1, },
+       { .center_freq = 2417, .hw_value = 2, },
+       { .center_freq = 2422, .hw_value = 3, },
+       { .center_freq = 2427, .hw_value = 4, },
+       { .center_freq = 2432, .hw_value = 5, },
+       { .center_freq = 2437, .hw_value = 6, },
+       { .center_freq = 2442, .hw_value = 7, },
+       { .center_freq = 2447, .hw_value = 8, },
+       { .center_freq = 2452, .hw_value = 9, },
+       { .center_freq = 2457, .hw_value = 10, },
+       { .center_freq = 2462, .hw_value = 11, },
+       { .center_freq = 2467, .hw_value = 12, },
+       { .center_freq = 2472, .hw_value = 13, },
+       { .center_freq = 2484, .hw_value = 14, },
+};
+
+static struct ieee80211_supported_band band_2GHz = {
+       .channels = p54_bgchannels,
+       .n_channels = ARRAY_SIZE(p54_bgchannels),
+       .bitrates = p54_bgrates,
+       .n_bitrates = ARRAY_SIZE(p54_bgrates),
+};
+
+static struct ieee80211_rate p54_arates[] = {
+       { .bitrate = 60, .hw_value = 4, },
+       { .bitrate = 90, .hw_value = 5, },
+       { .bitrate = 120, .hw_value = 6, },
+       { .bitrate = 180, .hw_value = 7, },
+       { .bitrate = 240, .hw_value = 8, },
+       { .bitrate = 360, .hw_value = 9, },
+       { .bitrate = 480, .hw_value = 10, },
+       { .bitrate = 540, .hw_value = 11, },
+};
+
+static struct ieee80211_channel p54_achannels[] = {
+       { .center_freq = 4920 },
+       { .center_freq = 4940 },
+       { .center_freq = 4960 },
+       { .center_freq = 4980 },
+       { .center_freq = 5040 },
+       { .center_freq = 5060 },
+       { .center_freq = 5080 },
+       { .center_freq = 5170 },
+       { .center_freq = 5180 },
+       { .center_freq = 5190 },
+       { .center_freq = 5200 },
+       { .center_freq = 5210 },
+       { .center_freq = 5220 },
+       { .center_freq = 5230 },
+       { .center_freq = 5240 },
+       { .center_freq = 5260 },
+       { .center_freq = 5280 },
+       { .center_freq = 5300 },
+       { .center_freq = 5320 },
+       { .center_freq = 5500 },
+       { .center_freq = 5520 },
+       { .center_freq = 5540 },
+       { .center_freq = 5560 },
+       { .center_freq = 5580 },
+       { .center_freq = 5600 },
+       { .center_freq = 5620 },
+       { .center_freq = 5640 },
+       { .center_freq = 5660 },
+       { .center_freq = 5680 },
+       { .center_freq = 5700 },
+       { .center_freq = 5745 },
+       { .center_freq = 5765 },
+       { .center_freq = 5785 },
+       { .center_freq = 5805 },
+       { .center_freq = 5825 },
+};
+
+static struct ieee80211_supported_band band_5GHz = {
+       .channels = p54_achannels,
+       .n_channels = ARRAY_SIZE(p54_achannels),
+       .bitrates = p54_arates,
+       .n_bitrates = ARRAY_SIZE(p54_arates),
+};
+
+static int p54_convert_rev0(struct ieee80211_hw *dev,
+                           struct pda_pa_curve_data *curve_data)
+{
+       struct p54_common *priv = dev->priv;
+       struct p54_pa_curve_data_sample *dst;
+       struct pda_pa_curve_data_sample_rev0 *src;
+       size_t cd_len = sizeof(*curve_data) +
+               (curve_data->points_per_channel*sizeof(*dst) + 2) *
+                curve_data->channels;
+       unsigned int i, j;
+       void *source, *target;
+
+       priv->curve_data = kmalloc(sizeof(*priv->curve_data) + cd_len,
+                                  GFP_KERNEL);
+       if (!priv->curve_data)
+               return -ENOMEM;
+
+       priv->curve_data->entries = curve_data->channels;
+       priv->curve_data->entry_size = sizeof(__le16) +
+               sizeof(*dst) * curve_data->points_per_channel;
+       priv->curve_data->offset = offsetof(struct pda_pa_curve_data, data);
+       priv->curve_data->len = cd_len;
+       memcpy(priv->curve_data->data, curve_data, sizeof(*curve_data));
+       source = curve_data->data;
+       target = ((struct pda_pa_curve_data *) priv->curve_data->data)->data;
+       for (i = 0; i < curve_data->channels; i++) {
+               __le16 *freq = source;
+               source += sizeof(__le16);
+               *((__le16 *)target) = *freq;
+               target += sizeof(__le16);
+               for (j = 0; j < curve_data->points_per_channel; j++) {
+                       dst = target;
+                       src = source;
+
+                       dst->rf_power = src->rf_power;
+                       dst->pa_detector = src->pa_detector;
+                       dst->data_64qam = src->pcv;
+                       /* "invent" the points for the other modulations */
+#define SUB(x, y) (u8)(((x) - (y)) > (x) ? 0 : (x) - (y))
+                       dst->data_16qam = SUB(src->pcv, 12);
+                       dst->data_qpsk = SUB(dst->data_16qam, 12);
+                       dst->data_bpsk = SUB(dst->data_qpsk, 12);
+                       dst->data_barker = SUB(dst->data_bpsk, 14);
+#undef SUB
+                       target += sizeof(*dst);
+                       source += sizeof(*src);
+               }
+       }
+
+       return 0;
+}
+
+static int p54_convert_rev1(struct ieee80211_hw *dev,
+                           struct pda_pa_curve_data *curve_data)
+{
+       struct p54_common *priv = dev->priv;
+       struct p54_pa_curve_data_sample *dst;
+       struct pda_pa_curve_data_sample_rev1 *src;
+       size_t cd_len = sizeof(*curve_data) +
+               (curve_data->points_per_channel*sizeof(*dst) + 2) *
+                curve_data->channels;
+       unsigned int i, j;
+       void *source, *target;
+
+       priv->curve_data = kzalloc(cd_len + sizeof(*priv->curve_data),
+                                  GFP_KERNEL);
+       if (!priv->curve_data)
+               return -ENOMEM;
+
+       priv->curve_data->entries = curve_data->channels;
+       priv->curve_data->entry_size = sizeof(__le16) +
+               sizeof(*dst) * curve_data->points_per_channel;
+       priv->curve_data->offset = offsetof(struct pda_pa_curve_data, data);
+       priv->curve_data->len = cd_len;
+       memcpy(priv->curve_data->data, curve_data, sizeof(*curve_data));
+       source = curve_data->data;
+       target = ((struct pda_pa_curve_data *) priv->curve_data->data)->data;
+       for (i = 0; i < curve_data->channels; i++) {
+               __le16 *freq = source;
+               source += sizeof(__le16);
+               *((__le16 *)target) = *freq;
+               target += sizeof(__le16);
+               for (j = 0; j < curve_data->points_per_channel; j++) {
+                       memcpy(target, source, sizeof(*src));
+
+                       target += sizeof(*dst);
+                       source += sizeof(*src);
+               }
+               source++;
+       }
+
+       return 0;
+}
+
+static const char *p54_rf_chips[] = { "INVALID-0", "Duette3", "Duette2",
+       "Frisbee", "Xbow", "Longbow", "INVALID-6", "INVALID-7" };
+
+static void p54_parse_rssical(struct ieee80211_hw *dev, void *data, int len,
+                            u16 type)
+{
+       struct p54_common *priv = dev->priv;
+       int offset = (type == PDR_RSSI_LINEAR_APPROXIMATION_EXTENDED) ? 2 : 0;
+       int entry_size = sizeof(struct pda_rssi_cal_entry) + offset;
+       int num_entries = (type == PDR_RSSI_LINEAR_APPROXIMATION) ? 1 : 2;
+       int i;
+
+       if (len != (entry_size * num_entries)) {
+               printk(KERN_ERR "%s: unknown rssi calibration data packing "
+                                " type:(%x) len:%d.\n",
+                      wiphy_name(dev->wiphy), type, len);
+
+               print_hex_dump_bytes("rssical:", DUMP_PREFIX_NONE,
+                                    data, len);
+
+               printk(KERN_ERR "%s: please report this issue.\n",
+                       wiphy_name(dev->wiphy));
+               return;
+       }
+
+       for (i = 0; i < num_entries; i++) {
+               struct pda_rssi_cal_entry *cal = data +
+                                                (offset + i * entry_size);
+               priv->rssical_db[i].mul = (s16) le16_to_cpu(cal->mul);
+               priv->rssical_db[i].add = (s16) le16_to_cpu(cal->add);
+       }
+}
+
+static void p54_parse_default_country(struct ieee80211_hw *dev,
+                                     void *data, int len)
+{
+       struct pda_country *country;
+
+       if (len != sizeof(*country)) {
+               printk(KERN_ERR "%s: found possible invalid default country "
+                               "eeprom entry. (entry size: %d)\n",
+                      wiphy_name(dev->wiphy), len);
+
+               print_hex_dump_bytes("country:", DUMP_PREFIX_NONE,
+                                    data, len);
+
+               printk(KERN_ERR "%s: please report this issue.\n",
+                       wiphy_name(dev->wiphy));
+               return;
+       }
+
+       country = (struct pda_country *) data;
+       if (country->flags == PDR_COUNTRY_CERT_CODE_PSEUDO)
+               regulatory_hint(dev->wiphy, country->alpha2);
+       else {
+               /* TODO:
+                * write a shared/common function that converts
+                * "Regulatory domain codes" (802.11-2007 14.8.2.2)
+                * into ISO/IEC 3166-1 alpha2 for regulatory_hint.
+                */
+       }
+}
+
+static int p54_convert_output_limits(struct ieee80211_hw *dev,
+                                    u8 *data, size_t len)
+{
+       struct p54_common *priv = dev->priv;
+
+       if (len < 2)
+               return -EINVAL;
+
+       if (data[0] != 0) {
+               printk(KERN_ERR "%s: unknown output power db revision:%x\n",
+                      wiphy_name(dev->wiphy), data[0]);
+               return -EINVAL;
+       }
+
+       if (2 + data[1] * sizeof(struct pda_channel_output_limit) > len)
+               return -EINVAL;
+
+       priv->output_limit = kmalloc(data[1] *
+               sizeof(struct pda_channel_output_limit) +
+               sizeof(*priv->output_limit), GFP_KERNEL);
+
+       if (!priv->output_limit)
+               return -ENOMEM;
+
+       priv->output_limit->offset = 0;
+       priv->output_limit->entries = data[1];
+       priv->output_limit->entry_size =
+               sizeof(struct pda_channel_output_limit);
+       priv->output_limit->len = priv->output_limit->entry_size *
+                                 priv->output_limit->entries +
+                                 priv->output_limit->offset;
+
+       memcpy(priv->output_limit->data, &data[2],
+              data[1] * sizeof(struct pda_channel_output_limit));
+
+       return 0;
+}
+
+static struct p54_cal_database *p54_convert_db(struct pda_custom_wrapper *src,
+                                              size_t total_len)
+{
+       struct p54_cal_database *dst;
+       size_t payload_len, entries, entry_size, offset;
+
+       payload_len = le16_to_cpu(src->len);
+       entries = le16_to_cpu(src->entries);
+       entry_size = le16_to_cpu(src->entry_size);
+       offset = le16_to_cpu(src->offset);
+       if (((entries * entry_size + offset) != payload_len) ||
+            (payload_len + sizeof(*src) != total_len))
+               return NULL;
+
+       dst = kmalloc(sizeof(*dst) + payload_len, GFP_KERNEL);
+       if (!dst)
+               return NULL;
+
+       dst->entries = entries;
+       dst->entry_size = entry_size;
+       dst->offset = offset;
+       dst->len = payload_len;
+
+       memcpy(dst->data, src->data, payload_len);
+       return dst;
+}
+
+int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len)
+{
+       struct p54_common *priv = dev->priv;
+       struct eeprom_pda_wrap *wrap = NULL;
+       struct pda_entry *entry;
+       unsigned int data_len, entry_len;
+       void *tmp;
+       int err;
+       u8 *end = (u8 *)eeprom + len;
+       u16 synth = 0;
+
+       wrap = (struct eeprom_pda_wrap *) eeprom;
+       entry = (void *)wrap->data + le16_to_cpu(wrap->len);
+
+       /* verify that at least the entry length/code fits */
+       while ((u8 *)entry <= end - sizeof(*entry)) {
+               entry_len = le16_to_cpu(entry->len);
+               data_len = ((entry_len - 1) << 1);
+
+               /* abort if entry exceeds whole structure */
+               if ((u8 *)entry + sizeof(*entry) + data_len > end)
+                       break;
+
+               switch (le16_to_cpu(entry->code)) {
+               case PDR_MAC_ADDRESS:
+                       if (data_len != ETH_ALEN)
+                               break;
+                       SET_IEEE80211_PERM_ADDR(dev, entry->data);
+                       break;
+               case PDR_PRISM_PA_CAL_OUTPUT_POWER_LIMITS:
+                       if (priv->output_limit)
+                               break;
+                       err = p54_convert_output_limits(dev, entry->data,
+                                                       data_len);
+                       if (err)
+                               goto err;
+                       break;
+               case PDR_PRISM_PA_CAL_CURVE_DATA: {
+                       struct pda_pa_curve_data *curve_data =
+                               (struct pda_pa_curve_data *)entry->data;
+                       if (data_len < sizeof(*curve_data)) {
+                               err = -EINVAL;
+                               goto err;
+                       }
+
+                       switch (curve_data->cal_method_rev) {
+                       case 0:
+                               err = p54_convert_rev0(dev, curve_data);
+                               break;
+                       case 1:
+                               err = p54_convert_rev1(dev, curve_data);
+                               break;
+                       default:
+                               printk(KERN_ERR "%s: unknown curve data "
+                                               "revision %d\n",
+                                               wiphy_name(dev->wiphy),
+                                               curve_data->cal_method_rev);
+                               err = -ENODEV;
+                               break;
+                       }
+                       if (err)
+                               goto err;
+                       }
+                       break;
+               case PDR_PRISM_ZIF_TX_IQ_CALIBRATION:
+                       priv->iq_autocal = kmalloc(data_len, GFP_KERNEL);
+                       if (!priv->iq_autocal) {
+                               err = -ENOMEM;
+                               goto err;
+                       }
+
+                       memcpy(priv->iq_autocal, entry->data, data_len);
+                       priv->iq_autocal_len = data_len / sizeof(struct pda_iq_autocal_entry);
+                       break;
+               case PDR_DEFAULT_COUNTRY:
+                       p54_parse_default_country(dev, entry->data, data_len);
+                       break;
+               case PDR_INTERFACE_LIST:
+                       tmp = entry->data;
+                       while ((u8 *)tmp < entry->data + data_len) {
+                               struct exp_if *exp_if = tmp;
+                               if (exp_if->if_id == cpu_to_le16(IF_ID_ISL39000))
+                                       synth = le16_to_cpu(exp_if->variant);
+                               tmp += sizeof(*exp_if);
+                       }
+                       break;
+               case PDR_HARDWARE_PLATFORM_COMPONENT_ID:
+                       if (data_len < 2)
+                               break;
+                       priv->version = *(u8 *)(entry->data + 1);
+                       break;
+               case PDR_RSSI_LINEAR_APPROXIMATION:
+               case PDR_RSSI_LINEAR_APPROXIMATION_DUAL_BAND:
+               case PDR_RSSI_LINEAR_APPROXIMATION_EXTENDED:
+                       p54_parse_rssical(dev, entry->data, data_len,
+                                         le16_to_cpu(entry->code));
+                       break;
+               case PDR_RSSI_LINEAR_APPROXIMATION_CUSTOM: {
+                       __le16 *src = (void *) entry->data;
+                       s16 *dst = (void *) &priv->rssical_db;
+                       int i;
+
+                       if (data_len != sizeof(priv->rssical_db)) {
+                               err = -EINVAL;
+                               goto err;
+                       }
+                       for (i = 0; i < sizeof(priv->rssical_db) /
+                                       sizeof(*src); i++)
+                               *(dst++) = (s16) le16_to_cpu(*(src++));
+                       }
+                       break;
+               case PDR_PRISM_PA_CAL_OUTPUT_POWER_LIMITS_CUSTOM: {
+                       struct pda_custom_wrapper *pda = (void *) entry->data;
+                       if (priv->output_limit || data_len < sizeof(*pda))
+                               break;
+                       priv->output_limit = p54_convert_db(pda, data_len);
+                       }
+                       break;
+               case PDR_PRISM_PA_CAL_CURVE_DATA_CUSTOM: {
+                       struct pda_custom_wrapper *pda = (void *) entry->data;
+                       if (priv->curve_data || data_len < sizeof(*pda))
+                               break;
+                       priv->curve_data = p54_convert_db(pda, data_len);
+                       }
+                       break;
+               case PDR_END:
+                       /* make it overrun */
+                       entry_len = len;
+                       break;
+               default:
+                       break;
+               }
+
+               entry = (void *)entry + (entry_len + 1)*2;
+       }
+
+       if (!synth || !priv->iq_autocal || !priv->output_limit ||
+           !priv->curve_data) {
+               printk(KERN_ERR "%s: not all required entries found in eeprom!\n",
+                       wiphy_name(dev->wiphy));
+               err = -EINVAL;
+               goto err;
+       }
+
+       priv->rxhw = synth & PDR_SYNTH_FRONTEND_MASK;
+       if (priv->rxhw == PDR_SYNTH_FRONTEND_XBOW)
+               p54_init_xbow_synth(priv);
+       if (!(synth & PDR_SYNTH_24_GHZ_DISABLED))
+               dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &band_2GHz;
+       if (!(synth & PDR_SYNTH_5_GHZ_DISABLED))
+               dev->wiphy->bands[IEEE80211_BAND_5GHZ] = &band_5GHz;
+       if ((synth & PDR_SYNTH_RX_DIV_MASK) == PDR_SYNTH_RX_DIV_SUPPORTED)
+               priv->rx_diversity_mask = 3;
+       if ((synth & PDR_SYNTH_TX_DIV_MASK) == PDR_SYNTH_TX_DIV_SUPPORTED)
+               priv->tx_diversity_mask = 3;
+
+       if (!is_valid_ether_addr(dev->wiphy->perm_addr)) {
+               u8 perm_addr[ETH_ALEN];
+
+               printk(KERN_WARNING "%s: Invalid hwaddr! Using randomly generated MAC addr\n",
+                       wiphy_name(dev->wiphy));
+               random_ether_addr(perm_addr);
+               SET_IEEE80211_PERM_ADDR(dev, perm_addr);
+       }
+
+       printk(KERN_INFO "%s: hwaddr %pM, MAC:isl38%02x RF:%s\n",
+               wiphy_name(dev->wiphy), dev->wiphy->perm_addr, priv->version,
+               p54_rf_chips[priv->rxhw]);
+
+       return 0;
+
+err:
+       kfree(priv->iq_autocal);
+       kfree(priv->output_limit);
+       kfree(priv->curve_data);
+       priv->iq_autocal = NULL;
+       priv->output_limit = NULL;
+       priv->curve_data = NULL;
+
+       printk(KERN_ERR "%s: eeprom parse failed!\n",
+               wiphy_name(dev->wiphy));
+       return err;
+}
+EXPORT_SYMBOL_GPL(p54_parse_eeprom);
+
+int p54_read_eeprom(struct ieee80211_hw *dev)
+{
+       struct p54_common *priv = dev->priv;
+       size_t eeprom_size = 0x2020, offset = 0, blocksize, maxblocksize;
+       int ret = -ENOMEM;
+       void *eeprom = NULL;
+
+       maxblocksize = EEPROM_READBACK_LEN;
+       if (priv->fw_var >= 0x509)
+               maxblocksize -= 0xc;
+       else
+               maxblocksize -= 0x4;
+
+       eeprom = kzalloc(eeprom_size, GFP_KERNEL);
+       if (unlikely(!eeprom))
+               goto free;
+
+       while (eeprom_size) {
+               blocksize = min(eeprom_size, maxblocksize);
+               ret = p54_download_eeprom(priv, (void *) (eeprom + offset),
+                                         offset, blocksize);
+               if (unlikely(ret))
+                       goto free;
+
+               offset += blocksize;
+               eeprom_size -= blocksize;
+       }
+
+       ret = p54_parse_eeprom(dev, eeprom, offset);
+free:
+       kfree(eeprom);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(p54_read_eeprom);
diff --git a/drivers/net/wireless/p54/eeprom.h b/drivers/net/wireless/p54/eeprom.h
new file mode 100644 (file)
index 0000000..9051aef
--- /dev/null
@@ -0,0 +1,226 @@
+/*
+ * eeprom specific definitions for mac80211 Prism54 drivers
+ *
+ * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
+ * Copyright (c) 2007-2009, Christian Lamparter <chunkeey@web.de>
+ *
+ * Based on:
+ * - the islsm (softmac prism54) driver, which is:
+ *   Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
+ *
+ * - LMAC API interface header file for STLC4560 (lmac_longbow.h)
+ *   Copyright (C) 2007 Conexant Systems, Inc.
+ *
+ * - islmvc driver
+ *   Copyright (C) 2001 Intersil Americas Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef EEPROM_H
+#define EEPROM_H
+
+/* PDA defines are Copyright (C) 2005 Nokia Corporation (taken from islsm_pda.h) */
+
+struct pda_entry {
+       __le16 len;     /* includes both code and data */
+       __le16 code;
+       u8 data[0];
+} __packed;
+
+struct eeprom_pda_wrap {
+       __le32 magic;
+       __le16 pad;
+       __le16 len;
+       __le32 arm_opcode;
+       u8 data[0];
+} __packed;
+
+struct p54_iq_autocal_entry {
+       __le16 iq_param[4];
+} __packed;
+
+struct pda_iq_autocal_entry {
+       __le16 freq;
+       struct p54_iq_autocal_entry params;
+} __packed;
+
+struct pda_channel_output_limit {
+       __le16 freq;
+       u8 val_bpsk;
+       u8 val_qpsk;
+       u8 val_16qam;
+       u8 val_64qam;
+       u8 rate_set_mask;
+       u8 rate_set_size;
+} __packed;
+
+struct pda_pa_curve_data_sample_rev0 {
+       u8 rf_power;
+       u8 pa_detector;
+       u8 pcv;
+} __packed;
+
+struct pda_pa_curve_data_sample_rev1 {
+       u8 rf_power;
+       u8 pa_detector;
+       u8 data_barker;
+       u8 data_bpsk;
+       u8 data_qpsk;
+       u8 data_16qam;
+       u8 data_64qam;
+} __packed;
+
+struct pda_pa_curve_data {
+       u8 cal_method_rev;
+       u8 channels;
+       u8 points_per_channel;
+       u8 padding;
+       u8 data[0];
+} __packed;
+
+struct pda_rssi_cal_entry {
+       __le16 mul;
+       __le16 add;
+} __packed;
+
+struct pda_country {
+       u8 regdomain;
+       u8 alpha2[2];
+       u8 flags;
+} __packed;
+
+struct pda_antenna_gain {
+       struct {
+               u8 gain_5GHz;   /* 0.25 dBi units */
+               u8 gain_2GHz;   /* 0.25 dBi units */
+       } __packed antenna[0];
+} __packed;
+
+struct pda_custom_wrapper {
+       __le16 entries;
+       __le16 entry_size;
+       __le16 offset;
+       __le16 len;
+       u8 data[0];
+} __packed;
+
+/*
+ * this defines the PDR codes used to build PDAs as defined in document
+ * number 553155. The current implementation mirrors version 1.1 of the
+ * document and lists only PDRs supported by the ARM platform.
+ */
+
+/* common and choice range (0x0000 - 0x0fff) */
+#define PDR_END                                        0x0000
+#define PDR_MANUFACTURING_PART_NUMBER          0x0001
+#define PDR_PDA_VERSION                                0x0002
+#define PDR_NIC_SERIAL_NUMBER                  0x0003
+#define PDR_NIC_RAM_SIZE                       0x0005
+#define PDR_RFMODEM_SUP_RANGE                  0x0006
+#define PDR_PRISM_MAC_SUP_RANGE                        0x0007
+#define PDR_NIC_ID                             0x0008
+
+#define PDR_MAC_ADDRESS                                0x0101
+#define PDR_REGULATORY_DOMAIN_LIST             0x0103 /* obsolete */
+#define PDR_ALLOWED_CHAN_SET                   0x0104
+#define PDR_DEFAULT_CHAN                       0x0105
+#define PDR_TEMPERATURE_TYPE                   0x0107
+
+#define PDR_IFR_SETTING                                0x0200
+#define PDR_RFR_SETTING                                0x0201
+#define PDR_3861_BASELINE_REG_SETTINGS         0x0202
+#define PDR_3861_SHADOW_REG_SETTINGS           0x0203
+#define PDR_3861_IFRF_REG_SETTINGS             0x0204
+
+#define PDR_3861_CHAN_CALIB_SET_POINTS         0x0300
+#define PDR_3861_CHAN_CALIB_INTEGRATOR         0x0301
+
+#define PDR_3842_PRISM_II_NIC_CONFIG           0x0400
+#define PDR_PRISM_USB_ID                       0x0401
+#define PDR_PRISM_PCI_ID                       0x0402
+#define PDR_PRISM_PCI_IF_CONFIG                        0x0403
+#define PDR_PRISM_PCI_PM_CONFIG                        0x0404
+
+#define PDR_3861_MF_TEST_CHAN_SET_POINTS       0x0900
+#define PDR_3861_MF_TEST_CHAN_INTEGRATORS      0x0901
+
+/* ARM range (0x1000 - 0x1fff) */
+#define PDR_COUNTRY_INFORMATION                        0x1000 /* obsolete */
+#define PDR_INTERFACE_LIST                     0x1001
+#define PDR_HARDWARE_PLATFORM_COMPONENT_ID     0x1002
+#define PDR_OEM_NAME                           0x1003
+#define PDR_PRODUCT_NAME                       0x1004
+#define PDR_UTF8_OEM_NAME                      0x1005
+#define PDR_UTF8_PRODUCT_NAME                  0x1006
+#define PDR_COUNTRY_LIST                       0x1007
+#define PDR_DEFAULT_COUNTRY                    0x1008
+
+#define PDR_ANTENNA_GAIN                       0x1100
+
+#define PDR_PRISM_INDIGO_PA_CALIBRATION_DATA   0x1901
+#define PDR_RSSI_LINEAR_APPROXIMATION          0x1902
+#define PDR_PRISM_PA_CAL_OUTPUT_POWER_LIMITS   0x1903
+#define PDR_PRISM_PA_CAL_CURVE_DATA            0x1904
+#define PDR_RSSI_LINEAR_APPROXIMATION_DUAL_BAND        0x1905
+#define PDR_PRISM_ZIF_TX_IQ_CALIBRATION                0x1906
+#define PDR_REGULATORY_POWER_LIMITS            0x1907
+#define PDR_RSSI_LINEAR_APPROXIMATION_EXTENDED 0x1908
+#define PDR_RADIATED_TRANSMISSION_CORRECTION   0x1909
+#define PDR_PRISM_TX_IQ_CALIBRATION            0x190a
+
+/* reserved range (0x2000 - 0x7fff) */
+
+/* customer range (0x8000 - 0xffff) */
+#define PDR_BASEBAND_REGISTERS                         0x8000
+#define PDR_PER_CHANNEL_BASEBAND_REGISTERS             0x8001
+
+/* used by our modificated eeprom image */
+#define PDR_RSSI_LINEAR_APPROXIMATION_CUSTOM           0xDEAD
+#define PDR_PRISM_PA_CAL_OUTPUT_POWER_LIMITS_CUSTOM    0xBEEF
+#define PDR_PRISM_PA_CAL_CURVE_DATA_CUSTOM             0xB05D
+
+/* Interface Definitions */
+#define PDR_INTERFACE_ROLE_SERVER      0x0000
+#define PDR_INTERFACE_ROLE_CLIENT      0x0001
+
+/* PDR definitions for default country & country list */
+#define PDR_COUNTRY_CERT_CODE          0x80
+#define PDR_COUNTRY_CERT_CODE_REAL     0x00
+#define PDR_COUNTRY_CERT_CODE_PSEUDO   0x80
+#define PDR_COUNTRY_CERT_BAND          0x40
+#define PDR_COUNTRY_CERT_BAND_2GHZ     0x00
+#define PDR_COUNTRY_CERT_BAND_5GHZ     0x40
+#define PDR_COUNTRY_CERT_IODOOR                0x30
+#define PDR_COUNTRY_CERT_IODOOR_BOTH   0x00
+#define PDR_COUNTRY_CERT_IODOOR_INDOOR 0x20
+#define PDR_COUNTRY_CERT_IODOOR_OUTDOOR        0x30
+#define PDR_COUNTRY_CERT_INDEX         0x0f
+
+/* Specific LMAC FW/HW variant definitions */
+#define PDR_SYNTH_FRONTEND_MASK                0x0007
+#define PDR_SYNTH_FRONTEND_DUETTE3     0x0001
+#define PDR_SYNTH_FRONTEND_DUETTE2     0x0002
+#define PDR_SYNTH_FRONTEND_FRISBEE     0x0003
+#define PDR_SYNTH_FRONTEND_XBOW                0x0004
+#define PDR_SYNTH_FRONTEND_LONGBOW     0x0005
+#define PDR_SYNTH_IQ_CAL_MASK          0x0018
+#define PDR_SYNTH_IQ_CAL_PA_DETECTOR   0x0000
+#define PDR_SYNTH_IQ_CAL_DISABLED      0x0008
+#define PDR_SYNTH_IQ_CAL_ZIF           0x0010
+#define PDR_SYNTH_FAA_SWITCH_MASK      0x0020
+#define PDR_SYNTH_FAA_SWITCH_ENABLED   0x0020
+#define PDR_SYNTH_24_GHZ_MASK          0x0040
+#define PDR_SYNTH_24_GHZ_DISABLED      0x0040
+#define PDR_SYNTH_5_GHZ_MASK           0x0080
+#define PDR_SYNTH_5_GHZ_DISABLED       0x0080
+#define PDR_SYNTH_RX_DIV_MASK          0x0100
+#define PDR_SYNTH_RX_DIV_SUPPORTED     0x0100
+#define PDR_SYNTH_TX_DIV_MASK          0x0200
+#define PDR_SYNTH_TX_DIV_SUPPORTED     0x0200
+#define PDR_SYNTH_ASM_MASK             0x0400
+#define PDR_SYNTH_ASM_XSWON            0x0400
+
+#endif /* EEPROM_H */
diff --git a/drivers/net/wireless/p54/fwio.c b/drivers/net/wireless/p54/fwio.c
new file mode 100644 (file)
index 0000000..dc4f3f5
--- /dev/null
@@ -0,0 +1,698 @@
+/*
+ * Firmware I/O code for mac80211 Prism54 drivers
+ *
+ * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
+ * Copyright (c) 2007-2009, Christian Lamparter <chunkeey@web.de>
+ * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
+ *
+ * Based on:
+ * - the islsm (softmac prism54) driver, which is:
+ *   Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
+ * - stlc45xx driver
+ *   Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/firmware.h>
+#include <linux/etherdevice.h>
+
+#include <net/mac80211.h>
+
+#include "p54.h"
+#include "eeprom.h"
+#include "lmac.h"
+
+int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw)
+{
+       struct p54_common *priv = dev->priv;
+       struct exp_if *exp_if;
+       struct bootrec *bootrec;
+       u32 *data = (u32 *)fw->data;
+       u32 *end_data = (u32 *)fw->data + (fw->size >> 2);
+       u8 *fw_version = NULL;
+       size_t len;
+       int i;
+       int maxlen;
+
+       if (priv->rx_start)
+               return 0;
+
+       while (data < end_data && *data)
+               data++;
+
+       while (data < end_data && !*data)
+               data++;
+
+       bootrec = (struct bootrec *) data;
+
+       while (bootrec->data <= end_data && (bootrec->data +
+              (len = le32_to_cpu(bootrec->len))) <= end_data) {
+               u32 code = le32_to_cpu(bootrec->code);
+               switch (code) {
+               case BR_CODE_COMPONENT_ID:
+                       priv->fw_interface = be32_to_cpup((__be32 *)
+                                            bootrec->data);
+                       switch (priv->fw_interface) {
+                       case FW_LM86:
+                       case FW_LM20:
+                       case FW_LM87: {
+                               char *iftype = (char *)bootrec->data;
+                               printk(KERN_INFO "%s: p54 detected a LM%c%c "
+                                                "firmware\n",
+                                       wiphy_name(priv->hw->wiphy),
+                                       iftype[2], iftype[3]);
+                               break;
+                               }
+                       case FW_FMAC:
+                       default:
+                               printk(KERN_ERR "%s: unsupported firmware\n",
+                                       wiphy_name(priv->hw->wiphy));
+                               return -ENODEV;
+                       }
+                       break;
+               case BR_CODE_COMPONENT_VERSION:
+                       /* 24 bytes should be enough for all firmwares */
+                       if (strnlen((unsigned char *) bootrec->data, 24) < 24)
+                               fw_version = (unsigned char *) bootrec->data;
+                       break;
+               case BR_CODE_DESCR: {
+                       struct bootrec_desc *desc =
+                               (struct bootrec_desc *)bootrec->data;
+                       priv->rx_start = le32_to_cpu(desc->rx_start);
+                       /* FIXME add sanity checking */
+                       priv->rx_end = le32_to_cpu(desc->rx_end) - 0x3500;
+                       priv->headroom = desc->headroom;
+                       priv->tailroom = desc->tailroom;
+                       priv->privacy_caps = desc->privacy_caps;
+                       priv->rx_keycache_size = desc->rx_keycache_size;
+                       if (le32_to_cpu(bootrec->len) == 11)
+                               priv->rx_mtu = le16_to_cpu(desc->rx_mtu);
+                       else
+                               priv->rx_mtu = (size_t)
+                                       0x620 - priv->tx_hdr_len;
+                       maxlen = priv->tx_hdr_len + /* USB devices */
+                                sizeof(struct p54_rx_data) +
+                                4 + /* rx alignment */
+                                IEEE80211_MAX_FRAG_THRESHOLD;
+                       if (priv->rx_mtu > maxlen && PAGE_SIZE == 4096) {
+                               printk(KERN_INFO "p54: rx_mtu reduced from %d "
+                                      "to %d\n", priv->rx_mtu, maxlen);
+                               priv->rx_mtu = maxlen;
+                       }
+                       break;
+                       }
+               case BR_CODE_EXPOSED_IF:
+                       exp_if = (struct exp_if *) bootrec->data;
+                       for (i = 0; i < (len * sizeof(*exp_if) / 4); i++)
+                               if (exp_if[i].if_id == cpu_to_le16(IF_ID_LMAC))
+                                       priv->fw_var = le16_to_cpu(exp_if[i].variant);
+                       break;
+               case BR_CODE_DEPENDENT_IF:
+                       break;
+               case BR_CODE_END_OF_BRA:
+               case LEGACY_BR_CODE_END_OF_BRA:
+                       end_data = NULL;
+                       break;
+               default:
+                       break;
+               }
+               bootrec = (struct bootrec *)&bootrec->data[len];
+       }
+
+       if (fw_version)
+               printk(KERN_INFO "%s: FW rev %s - Softmac protocol %x.%x\n",
+                       wiphy_name(priv->hw->wiphy), fw_version,
+                       priv->fw_var >> 8, priv->fw_var & 0xff);
+
+       if (priv->fw_var < 0x500)
+               printk(KERN_INFO "%s: you are using an obsolete firmware. "
+                      "visit http://wireless.kernel.org/en/users/Drivers/p54 "
+                      "and grab one for \"kernel >= 2.6.28\"!\n",
+                       wiphy_name(priv->hw->wiphy));
+
+       if (priv->fw_var >= 0x300) {
+               /* Firmware supports QoS, use it! */
+
+               if (priv->fw_var >= 0x500) {
+                       priv->tx_stats[P54_QUEUE_AC_VO].limit = 16;
+                       priv->tx_stats[P54_QUEUE_AC_VI].limit = 16;
+                       priv->tx_stats[P54_QUEUE_AC_BE].limit = 16;
+                       priv->tx_stats[P54_QUEUE_AC_BK].limit = 16;
+               } else {
+                       priv->tx_stats[P54_QUEUE_AC_VO].limit = 3;
+                       priv->tx_stats[P54_QUEUE_AC_VI].limit = 4;
+                       priv->tx_stats[P54_QUEUE_AC_BE].limit = 3;
+                       priv->tx_stats[P54_QUEUE_AC_BK].limit = 2;
+               }
+               priv->hw->queues = P54_QUEUE_AC_NUM;
+       }
+
+       printk(KERN_INFO "%s: cryptographic accelerator "
+              "WEP:%s, TKIP:%s, CCMP:%s\n", wiphy_name(priv->hw->wiphy),
+               (priv->privacy_caps & BR_DESC_PRIV_CAP_WEP) ? "YES" :
+               "no", (priv->privacy_caps & (BR_DESC_PRIV_CAP_TKIP |
+               BR_DESC_PRIV_CAP_MICHAEL)) ? "YES" : "no",
+               (priv->privacy_caps & BR_DESC_PRIV_CAP_AESCCMP) ?
+               "YES" : "no");
+
+       if (priv->rx_keycache_size) {
+               /*
+                * NOTE:
+                *
+                * The firmware provides at most 255 (0 - 254) slots
+                * for keys which are then used to offload decryption.
+                * As a result the 255 entry (aka 0xff) can be used
+                * safely by the driver to mark keys that didn't fit
+                * into the full cache. This trick saves us from
+                * keeping a extra list for uploaded keys.
+                */
+
+               priv->used_rxkeys = kzalloc(BITS_TO_LONGS(
+                       priv->rx_keycache_size), GFP_KERNEL);
+
+               if (!priv->used_rxkeys)
+                       return -ENOMEM;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(p54_parse_firmware);
+
+static struct sk_buff *p54_alloc_skb(struct p54_common *priv, u16 hdr_flags,
+                                    u16 payload_len, u16 type, gfp_t memflags)
+{
+       struct p54_hdr *hdr;
+       struct sk_buff *skb;
+       size_t frame_len = sizeof(*hdr) + payload_len;
+
+       if (frame_len > P54_MAX_CTRL_FRAME_LEN)
+               return NULL;
+
+       if (unlikely(skb_queue_len(&priv->tx_pending) > 64))
+               return NULL;
+
+       skb = __dev_alloc_skb(priv->tx_hdr_len + frame_len, memflags);
+       if (!skb)
+               return NULL;
+       skb_reserve(skb, priv->tx_hdr_len);
+
+       hdr = (struct p54_hdr *) skb_put(skb, sizeof(*hdr));
+       hdr->flags = cpu_to_le16(hdr_flags);
+       hdr->len = cpu_to_le16(payload_len);
+       hdr->type = cpu_to_le16(type);
+       hdr->tries = hdr->rts_tries = 0;
+       return skb;
+}
+
+int p54_download_eeprom(struct p54_common *priv, void *buf,
+                       u16 offset, u16 len)
+{
+       struct p54_eeprom_lm86 *eeprom_hdr;
+       struct sk_buff *skb;
+       size_t eeprom_hdr_size;
+       int ret = 0;
+
+       if (priv->fw_var >= 0x509)
+               eeprom_hdr_size = sizeof(*eeprom_hdr);
+       else
+               eeprom_hdr_size = 0x4;
+
+       skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL, eeprom_hdr_size +
+                           len, P54_CONTROL_TYPE_EEPROM_READBACK,
+                           GFP_KERNEL);
+       if (unlikely(!skb))
+               return -ENOMEM;
+
+       mutex_lock(&priv->eeprom_mutex);
+       priv->eeprom = buf;
+       eeprom_hdr = (struct p54_eeprom_lm86 *) skb_put(skb,
+               eeprom_hdr_size + len);
+
+       if (priv->fw_var < 0x509) {
+               eeprom_hdr->v1.offset = cpu_to_le16(offset);
+               eeprom_hdr->v1.len = cpu_to_le16(len);
+       } else {
+               eeprom_hdr->v2.offset = cpu_to_le32(offset);
+               eeprom_hdr->v2.len = cpu_to_le16(len);
+               eeprom_hdr->v2.magic2 = 0xf;
+               memcpy(eeprom_hdr->v2.magic, (const char *)"LOCK", 4);
+       }
+
+       p54_tx(priv, skb);
+
+       if (!wait_for_completion_interruptible_timeout(
+            &priv->eeprom_comp, HZ)) {
+               printk(KERN_ERR "%s: device does not respond!\n",
+                      wiphy_name(priv->hw->wiphy));
+               ret = -EBUSY;
+       }
+       priv->eeprom = NULL;
+       mutex_unlock(&priv->eeprom_mutex);
+       return ret;
+}
+
+int p54_update_beacon_tim(struct p54_common *priv, u16 aid, bool set)
+{
+       struct sk_buff *skb;
+       struct p54_tim *tim;
+
+       skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*tim),
+                           P54_CONTROL_TYPE_TIM, GFP_ATOMIC);
+       if (unlikely(!skb))
+               return -ENOMEM;
+
+       tim = (struct p54_tim *) skb_put(skb, sizeof(*tim));
+       tim->count = 1;
+       tim->entry[0] = cpu_to_le16(set ? (aid | 0x8000) : aid);
+       p54_tx(priv, skb);
+       return 0;
+}
+
+int p54_sta_unlock(struct p54_common *priv, u8 *addr)
+{
+       struct sk_buff *skb;
+       struct p54_sta_unlock *sta;
+
+       skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*sta),
+                           P54_CONTROL_TYPE_PSM_STA_UNLOCK, GFP_ATOMIC);
+       if (unlikely(!skb))
+               return -ENOMEM;
+
+       sta = (struct p54_sta_unlock *)skb_put(skb, sizeof(*sta));
+       memcpy(sta->addr, addr, ETH_ALEN);
+       p54_tx(priv, skb);
+       return 0;
+}
+
+int p54_tx_cancel(struct p54_common *priv, __le32 req_id)
+{
+       struct sk_buff *skb;
+       struct p54_txcancel *cancel;
+       u32 _req_id = le32_to_cpu(req_id);
+
+       if (unlikely(_req_id < priv->rx_start || _req_id > priv->rx_end))
+               return -EINVAL;
+
+       skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*cancel),
+                           P54_CONTROL_TYPE_TXCANCEL, GFP_ATOMIC);
+       if (unlikely(!skb))
+               return -ENOMEM;
+
+       cancel = (struct p54_txcancel *)skb_put(skb, sizeof(*cancel));
+       cancel->req_id = req_id;
+       p54_tx(priv, skb);
+       return 0;
+}
+
+int p54_setup_mac(struct p54_common *priv)
+{
+       struct sk_buff *skb;
+       struct p54_setup_mac *setup;
+       u16 mode;
+
+       skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*setup),
+                           P54_CONTROL_TYPE_SETUP, GFP_ATOMIC);
+       if (!skb)
+               return -ENOMEM;
+
+       setup = (struct p54_setup_mac *) skb_put(skb, sizeof(*setup));
+       if (priv->hw->conf.radio_enabled) {
+               switch (priv->mode) {
+               case NL80211_IFTYPE_STATION:
+                       mode = P54_FILTER_TYPE_STATION;
+                       break;
+               case NL80211_IFTYPE_AP:
+                       mode = P54_FILTER_TYPE_AP;
+                       break;
+               case NL80211_IFTYPE_ADHOC:
+               case NL80211_IFTYPE_MESH_POINT:
+                       mode = P54_FILTER_TYPE_IBSS;
+                       break;
+               case NL80211_IFTYPE_MONITOR:
+                       mode = P54_FILTER_TYPE_PROMISCUOUS;
+                       break;
+               default:
+                       mode = P54_FILTER_TYPE_HIBERNATE;
+                       break;
+               }
+
+               /*
+                * "TRANSPARENT and PROMISCUOUS are mutually exclusive"
+                * STSW45X0C LMAC API - page 12
+                */
+               if (((priv->filter_flags & FIF_PROMISC_IN_BSS) ||
+                    (priv->filter_flags & FIF_OTHER_BSS)) &&
+                   (mode != P54_FILTER_TYPE_PROMISCUOUS))
+                       mode |= P54_FILTER_TYPE_TRANSPARENT;
+       } else
+               mode = P54_FILTER_TYPE_HIBERNATE;
+
+       setup->mac_mode = cpu_to_le16(mode);
+       memcpy(setup->mac_addr, priv->mac_addr, ETH_ALEN);
+       memcpy(setup->bssid, priv->bssid, ETH_ALEN);
+       setup->rx_antenna = 2 & priv->rx_diversity_mask; /* automatic */
+       setup->rx_align = 0;
+       if (priv->fw_var < 0x500) {
+               setup->v1.basic_rate_mask = cpu_to_le32(priv->basic_rate_mask);
+               memset(setup->v1.rts_rates, 0, 8);
+               setup->v1.rx_addr = cpu_to_le32(priv->rx_end);
+               setup->v1.max_rx = cpu_to_le16(priv->rx_mtu);
+               setup->v1.rxhw = cpu_to_le16(priv->rxhw);
+               setup->v1.wakeup_timer = cpu_to_le16(priv->wakeup_timer);
+               setup->v1.unalloc0 = cpu_to_le16(0);
+       } else {
+               setup->v2.rx_addr = cpu_to_le32(priv->rx_end);
+               setup->v2.max_rx = cpu_to_le16(priv->rx_mtu);
+               setup->v2.rxhw = cpu_to_le16(priv->rxhw);
+               setup->v2.timer = cpu_to_le16(priv->wakeup_timer);
+               setup->v2.truncate = cpu_to_le16(48896);
+               setup->v2.basic_rate_mask = cpu_to_le32(priv->basic_rate_mask);
+               setup->v2.sbss_offset = 0;
+               setup->v2.mcast_window = 0;
+               setup->v2.rx_rssi_threshold = 0;
+               setup->v2.rx_ed_threshold = 0;
+               setup->v2.ref_clock = cpu_to_le32(644245094);
+               setup->v2.lpf_bandwidth = cpu_to_le16(65535);
+               setup->v2.osc_start_delay = cpu_to_le16(65535);
+       }
+       p54_tx(priv, skb);
+       return 0;
+}
+
+int p54_scan(struct p54_common *priv, u16 mode, u16 dwell)
+{
+       struct sk_buff *skb;
+       struct p54_hdr *hdr;
+       struct p54_scan_head *head;
+       struct p54_iq_autocal_entry *iq_autocal;
+       union p54_scan_body_union *body;
+       struct p54_scan_tail_rate *rate;
+       struct pda_rssi_cal_entry *rssi;
+       unsigned int i;
+       void *entry;
+       int band = priv->hw->conf.channel->band;
+       __le16 freq = cpu_to_le16(priv->hw->conf.channel->center_freq);
+
+       skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*head) +
+                           2 + sizeof(*iq_autocal) + sizeof(*body) +
+                           sizeof(*rate) + 2 * sizeof(*rssi),
+                           P54_CONTROL_TYPE_SCAN, GFP_ATOMIC);
+       if (!skb)
+               return -ENOMEM;
+
+       head = (struct p54_scan_head *) skb_put(skb, sizeof(*head));
+       memset(head->scan_params, 0, sizeof(head->scan_params));
+       head->mode = cpu_to_le16(mode);
+       head->dwell = cpu_to_le16(dwell);
+       head->freq = freq;
+
+       if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW) {
+               __le16 *pa_power_points = (__le16 *) skb_put(skb, 2);
+               *pa_power_points = cpu_to_le16(0x0c);
+       }
+
+       iq_autocal = (void *) skb_put(skb, sizeof(*iq_autocal));
+       for (i = 0; i < priv->iq_autocal_len; i++) {
+               if (priv->iq_autocal[i].freq != freq)
+                       continue;
+
+               memcpy(iq_autocal, &priv->iq_autocal[i].params,
+                      sizeof(struct p54_iq_autocal_entry));
+               break;
+       }
+       if (i == priv->iq_autocal_len)
+               goto err;
+
+       if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW)
+               body = (void *) skb_put(skb, sizeof(body->longbow));
+       else
+               body = (void *) skb_put(skb, sizeof(body->normal));
+
+       for (i = 0; i < priv->output_limit->entries; i++) {
+               __le16 *entry_freq = (void *) (priv->output_limit->data +
+                                    priv->output_limit->entry_size * i);
+
+               if (*entry_freq != freq)
+                       continue;
+
+               if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW) {
+                       memcpy(&body->longbow.power_limits,
+                              (void *) entry_freq + sizeof(__le16),
+                              priv->output_limit->entry_size);
+               } else {
+                       struct pda_channel_output_limit *limits =
+                              (void *) entry_freq;
+
+                       body->normal.val_barker = 0x38;
+                       body->normal.val_bpsk = body->normal.dup_bpsk =
+                               limits->val_bpsk;
+                       body->normal.val_qpsk = body->normal.dup_qpsk =
+                               limits->val_qpsk;
+                       body->normal.val_16qam = body->normal.dup_16qam =
+                               limits->val_16qam;
+                       body->normal.val_64qam = body->normal.dup_64qam =
+                               limits->val_64qam;
+               }
+               break;
+       }
+       if (i == priv->output_limit->entries)
+               goto err;
+
+       entry = (void *)(priv->curve_data->data + priv->curve_data->offset);
+       for (i = 0; i < priv->curve_data->entries; i++) {
+               if (*((__le16 *)entry) != freq) {
+                       entry += priv->curve_data->entry_size;
+                       continue;
+               }
+
+               if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW) {
+                       memcpy(&body->longbow.curve_data,
+                               (void *) entry + sizeof(__le16),
+                               priv->curve_data->entry_size);
+               } else {
+                       struct p54_scan_body *chan = &body->normal;
+                       struct pda_pa_curve_data *curve_data =
+                               (void *) priv->curve_data->data;
+
+                       entry += sizeof(__le16);
+                       chan->pa_points_per_curve = 8;
+                       memset(chan->curve_data, 0, sizeof(*chan->curve_data));
+                       memcpy(chan->curve_data, entry,
+                              sizeof(struct p54_pa_curve_data_sample) *
+                              min((u8)8, curve_data->points_per_channel));
+               }
+               break;
+       }
+       if (i == priv->curve_data->entries)
+               goto err;
+
+       if ((priv->fw_var >= 0x500) && (priv->fw_var < 0x509)) {
+               rate = (void *) skb_put(skb, sizeof(*rate));
+               rate->basic_rate_mask = cpu_to_le32(priv->basic_rate_mask);
+               for (i = 0; i < sizeof(rate->rts_rates); i++)
+                       rate->rts_rates[i] = i;
+       }
+
+       rssi = (struct pda_rssi_cal_entry *) skb_put(skb, sizeof(*rssi));
+       rssi->mul = cpu_to_le16(priv->rssical_db[band].mul);
+       rssi->add = cpu_to_le16(priv->rssical_db[band].add);
+       if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW) {
+               /* Longbow frontend needs ever more */
+               rssi = (void *) skb_put(skb, sizeof(*rssi));
+               rssi->mul = cpu_to_le16(priv->rssical_db[band].longbow_unkn);
+               rssi->add = cpu_to_le16(priv->rssical_db[band].longbow_unk2);
+       }
+
+       if (priv->fw_var >= 0x509) {
+               rate = (void *) skb_put(skb, sizeof(*rate));
+               rate->basic_rate_mask = cpu_to_le32(priv->basic_rate_mask);
+               for (i = 0; i < sizeof(rate->rts_rates); i++)
+                       rate->rts_rates[i] = i;
+       }
+
+       hdr = (struct p54_hdr *) skb->data;
+       hdr->len = cpu_to_le16(skb->len - sizeof(*hdr));
+
+       p54_tx(priv, skb);
+       return 0;
+
+err:
+       printk(KERN_ERR "%s: frequency change to channel %d failed.\n",
+              wiphy_name(priv->hw->wiphy), ieee80211_frequency_to_channel(
+              priv->hw->conf.channel->center_freq));
+
+       dev_kfree_skb_any(skb);
+       return -EINVAL;
+}
+
+int p54_set_leds(struct p54_common *priv)
+{
+       struct sk_buff *skb;
+       struct p54_led *led;
+
+       skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*led),
+                           P54_CONTROL_TYPE_LED, GFP_ATOMIC);
+       if (unlikely(!skb))
+               return -ENOMEM;
+
+       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);
+       p54_tx(priv, skb);
+       return 0;
+}
+
+int p54_set_edcf(struct p54_common *priv)
+{
+       struct sk_buff *skb;
+       struct p54_edcf *edcf;
+
+       skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*edcf),
+                           P54_CONTROL_TYPE_DCFINIT, GFP_ATOMIC);
+       if (unlikely(!skb))
+               return -ENOMEM;
+
+       edcf = (struct p54_edcf *)skb_put(skb, sizeof(*edcf));
+       if (priv->use_short_slot) {
+               edcf->slottime = 9;
+               edcf->sifs = 0x10;
+               edcf->eofpad = 0x00;
+       } else {
+               edcf->slottime = 20;
+               edcf->sifs = 0x0a;
+               edcf->eofpad = 0x06;
+       }
+       /* (see prism54/isl_oid.h for further details) */
+       edcf->frameburst = cpu_to_le16(0);
+       edcf->round_trip_delay = cpu_to_le16(0);
+       edcf->flags = 0;
+       memset(edcf->mapping, 0, sizeof(edcf->mapping));
+       memcpy(edcf->queue, priv->qos_params, sizeof(edcf->queue));
+       p54_tx(priv, skb);
+       return 0;
+}
+
+int p54_set_ps(struct p54_common *priv)
+{
+       struct sk_buff *skb;
+       struct p54_psm *psm;
+       unsigned int i;
+       u16 mode;
+
+       if (priv->hw->conf.flags & IEEE80211_CONF_PS)
+               mode = P54_PSM | P54_PSM_BEACON_TIMEOUT | P54_PSM_DTIM |
+                      P54_PSM_CHECKSUM | P54_PSM_MCBC;
+       else
+               mode = P54_PSM_CAM;
+
+       skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*psm),
+                           P54_CONTROL_TYPE_PSM, GFP_ATOMIC);
+       if (!skb)
+               return -ENOMEM;
+
+       psm = (struct p54_psm *)skb_put(skb, sizeof(*psm));
+       psm->mode = cpu_to_le16(mode);
+       psm->aid = cpu_to_le16(priv->aid);
+       for (i = 0; i < ARRAY_SIZE(psm->intervals); i++) {
+               psm->intervals[i].interval =
+                       cpu_to_le16(priv->hw->conf.listen_interval);
+               psm->intervals[i].periods = cpu_to_le16(1);
+       }
+
+       psm->beacon_rssi_skip_max = 200;
+       psm->rssi_delta_threshold = 0;
+       psm->nr = 10;
+       psm->exclude[0] = 0;
+
+       p54_tx(priv, skb);
+       return 0;
+}
+
+int p54_init_xbow_synth(struct p54_common *priv)
+{
+       struct sk_buff *skb;
+       struct p54_xbow_synth *xbow;
+
+       skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*xbow),
+                           P54_CONTROL_TYPE_XBOW_SYNTH_CFG, GFP_KERNEL);
+       if (unlikely(!skb))
+               return -ENOMEM;
+
+       xbow = (struct p54_xbow_synth *)skb_put(skb, sizeof(*xbow));
+       xbow->magic1 = cpu_to_le16(0x1);
+       xbow->magic2 = cpu_to_le16(0x2);
+       xbow->freq = cpu_to_le16(5390);
+       memset(xbow->padding, 0, sizeof(xbow->padding));
+       p54_tx(priv, skb);
+       return 0;
+}
+
+int p54_upload_key(struct p54_common *priv, u8 algo, int slot, u8 idx, u8 len,
+                  u8 *addr, u8* key)
+{
+       struct sk_buff *skb;
+       struct p54_keycache *rxkey;
+
+       skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*rxkey),
+                           P54_CONTROL_TYPE_RX_KEYCACHE, GFP_KERNEL);
+       if (unlikely(!skb))
+               return -ENOMEM;
+
+       rxkey = (struct p54_keycache *)skb_put(skb, sizeof(*rxkey));
+       rxkey->entry = slot;
+       rxkey->key_id = idx;
+       rxkey->key_type = algo;
+       if (addr)
+               memcpy(rxkey->mac, addr, ETH_ALEN);
+       else
+               memset(rxkey->mac, ~0, ETH_ALEN);
+
+       switch (algo) {
+       case P54_CRYPTO_WEP:
+       case P54_CRYPTO_AESCCMP:
+               rxkey->key_len = min_t(u8, 16, len);
+               memcpy(rxkey->key, key, rxkey->key_len);
+               break;
+
+       case P54_CRYPTO_TKIPMICHAEL:
+               rxkey->key_len = 24;
+               memcpy(rxkey->key, key, 16);
+               memcpy(&(rxkey->key[16]), &(key
+                       [NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY]), 8);
+               break;
+
+       case P54_CRYPTO_NONE:
+               rxkey->key_len = 0;
+               memset(rxkey->key, 0, sizeof(rxkey->key));
+               break;
+
+       default:
+               printk(KERN_ERR "%s: invalid cryptographic algorithm: %d\n",
+                      wiphy_name(priv->hw->wiphy), algo);
+               dev_kfree_skb(skb);
+               return -EINVAL;
+       }
+
+       p54_tx(priv, skb);
+       return 0;
+}
+
+int p54_fetch_statistics(struct p54_common *priv)
+{
+       struct sk_buff *skb;
+
+       skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL,
+                           sizeof(struct p54_statistics),
+                           P54_CONTROL_TYPE_STAT_READBACK, GFP_KERNEL);
+       if (!skb)
+               return -ENOMEM;
+
+       p54_tx(priv, skb);
+       return 0;
+}
diff --git a/drivers/net/wireless/p54/led.c b/drivers/net/wireless/p54/led.c
new file mode 100644 (file)
index 0000000..c00115b
--- /dev/null
@@ -0,0 +1,163 @@
+/*
+ * Common code for mac80211 Prism54 drivers
+ *
+ * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
+ * Copyright (c) 2007-2009, Christian Lamparter <chunkeey@web.de>
+ * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
+ *
+ * Based on:
+ * - the islsm (softmac prism54) driver, which is:
+ *   Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
+ * - stlc45xx driver
+ *   Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/firmware.h>
+#include <linux/etherdevice.h>
+
+#include <net/mac80211.h>
+#ifdef CONFIG_P54_LEDS
+#include <linux/leds.h>
+#endif /* CONFIG_P54_LEDS */
+
+#include "p54.h"
+#include "lmac.h"
+
+static void p54_update_leds(struct work_struct *work)
+{
+       struct p54_common *priv = container_of(work, struct p54_common,
+                                              led_work.work);
+       int err, i, tmp, blink_delay = 400;
+       bool rerun = false;
+
+       /* Don't toggle the LED, when the device is down. */
+       if (priv->mode == NL80211_IFTYPE_UNSPECIFIED)
+               return ;
+
+       for (i = 0; i < ARRAY_SIZE(priv->leds); i++)
+               if (priv->leds[i].toggled) {
+                       priv->softled_state |= BIT(i);
+
+                       tmp = 70 + 200 / (priv->leds[i].toggled);
+                       if (tmp < blink_delay)
+                               blink_delay = tmp;
+
+                       if (priv->leds[i].led_dev.brightness == LED_OFF)
+                               rerun = true;
+
+                       priv->leds[i].toggled =
+                               !!priv->leds[i].led_dev.brightness;
+               } else
+                       priv->softled_state &= ~BIT(i);
+
+       err = p54_set_leds(priv);
+       if (err && net_ratelimit())
+               printk(KERN_ERR "%s: failed to update LEDs (%d).\n",
+                       wiphy_name(priv->hw->wiphy), err);
+
+       if (rerun)
+               queue_delayed_work(priv->hw->workqueue, &priv->led_work,
+                       msecs_to_jiffies(blink_delay));
+}
+
+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;
+
+       if (priv->mode == NL80211_IFTYPE_UNSPECIFIED)
+               return ;
+
+       if ((brightness) && (led->registered)) {
+               led->toggled++;
+               queue_delayed_work(priv->hw->workqueue, &priv->led_work,
+                                  HZ/10);
+       }
+}
+
+static int p54_register_led(struct p54_common *priv,
+                           unsigned int led_index,
+                           char *name, char *trigger)
+{
+       struct p54_led_dev *led = &priv->leds[led_index];
+       int err;
+
+       if (led->registered)
+               return -EEXIST;
+
+       snprintf(led->name, sizeof(led->name), "p54-%s::%s",
+                wiphy_name(priv->hw->wiphy), name);
+       led->hw_dev = priv->hw;
+       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(priv->hw->wiphy), &led->led_dev);
+       if (err)
+               printk(KERN_ERR "%s: Failed to register %s LED.\n",
+                       wiphy_name(priv->hw->wiphy), name);
+       else
+               led->registered = 1;
+
+       return err;
+}
+
+int p54_init_leds(struct p54_common *priv)
+{
+       int err;
+
+       /*
+        * TODO:
+        * Figure out if the EEPROM contains some hints about the number
+        * of available/programmable LEDs of the device.
+        */
+
+       INIT_DELAYED_WORK(&priv->led_work, p54_update_leds);
+
+       err = p54_register_led(priv, 0, "assoc",
+                              ieee80211_get_assoc_led_name(priv->hw));
+       if (err)
+               return err;
+
+       err = p54_register_led(priv, 1, "tx",
+                              ieee80211_get_tx_led_name(priv->hw));
+       if (err)
+               return err;
+
+       err = p54_register_led(priv, 2, "rx",
+                              ieee80211_get_rx_led_name(priv->hw));
+       if (err)
+               return err;
+
+       err = p54_register_led(priv, 3, "radio",
+                              ieee80211_get_radio_led_name(priv->hw));
+       if (err)
+               return err;
+
+       err = p54_set_leds(priv);
+       return err;
+}
+
+void p54_unregister_leds(struct p54_common *priv)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(priv->leds); i++) {
+               if (priv->leds[i].registered) {
+                       priv->leds[i].registered = false;
+                       priv->leds[i].toggled = 0;
+                       led_classdev_unregister(&priv->leds[i].led_dev);
+               }
+       }
+
+       cancel_delayed_work_sync(&priv->led_work);
+}
diff --git a/drivers/net/wireless/p54/lmac.h b/drivers/net/wireless/p54/lmac.h
new file mode 100644 (file)
index 0000000..0496cff
--- /dev/null
@@ -0,0 +1,551 @@
+/*
+ * LMAC Interface specific definitions for mac80211 Prism54 drivers
+ *
+ * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
+ * Copyright (c) 2007 - 2009, Christian Lamparter <chunkeey@web.de>
+ *
+ * Based on:
+ * - the islsm (softmac prism54) driver, which is:
+ *   Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
+ *
+ * - LMAC API interface header file for STLC4560 (lmac_longbow.h)
+ *   Copyright (C) 2007 Conexant Systems, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef LMAC_H
+#define LMAC_H
+
+enum p54_control_frame_types {
+       P54_CONTROL_TYPE_SETUP = 0,
+       P54_CONTROL_TYPE_SCAN,
+       P54_CONTROL_TYPE_TRAP,
+       P54_CONTROL_TYPE_DCFINIT,
+       P54_CONTROL_TYPE_RX_KEYCACHE,
+       P54_CONTROL_TYPE_TIM,
+       P54_CONTROL_TYPE_PSM,
+       P54_CONTROL_TYPE_TXCANCEL,
+       P54_CONTROL_TYPE_TXDONE,
+       P54_CONTROL_TYPE_BURST,
+       P54_CONTROL_TYPE_STAT_READBACK,
+       P54_CONTROL_TYPE_BBP,
+       P54_CONTROL_TYPE_EEPROM_READBACK,
+       P54_CONTROL_TYPE_LED,
+       P54_CONTROL_TYPE_GPIO,
+       P54_CONTROL_TYPE_TIMER,
+       P54_CONTROL_TYPE_MODULATION,
+       P54_CONTROL_TYPE_SYNTH_CONFIG,
+       P54_CONTROL_TYPE_DETECTOR_VALUE,
+       P54_CONTROL_TYPE_XBOW_SYNTH_CFG,
+       P54_CONTROL_TYPE_CCE_QUIET,
+       P54_CONTROL_TYPE_PSM_STA_UNLOCK,
+       P54_CONTROL_TYPE_PCS,
+       P54_CONTROL_TYPE_BT_BALANCER = 28,
+       P54_CONTROL_TYPE_GROUP_ADDRESS_TABLE = 30,
+       P54_CONTROL_TYPE_ARPTABLE = 31,
+       P54_CONTROL_TYPE_BT_OPTIONS = 35,
+};
+
+#define P54_HDR_FLAG_CONTROL           BIT(15)
+#define P54_HDR_FLAG_CONTROL_OPSET     (BIT(15) + BIT(0))
+#define P54_HDR_FLAG_DATA_ALIGN                BIT(14)
+
+#define P54_HDR_FLAG_DATA_OUT_PROMISC          BIT(0)
+#define P54_HDR_FLAG_DATA_OUT_TIMESTAMP                BIT(1)
+#define P54_HDR_FLAG_DATA_OUT_SEQNR            BIT(2)
+#define P54_HDR_FLAG_DATA_OUT_BIT3             BIT(3)
+#define P54_HDR_FLAG_DATA_OUT_BURST            BIT(4)
+#define P54_HDR_FLAG_DATA_OUT_NOCANCEL         BIT(5)
+#define P54_HDR_FLAG_DATA_OUT_CLEARTIM         BIT(6)
+#define P54_HDR_FLAG_DATA_OUT_HITCHHIKE                BIT(7)
+#define P54_HDR_FLAG_DATA_OUT_COMPRESS         BIT(8)
+#define P54_HDR_FLAG_DATA_OUT_CONCAT           BIT(9)
+#define P54_HDR_FLAG_DATA_OUT_PCS_ACCEPT       BIT(10)
+#define P54_HDR_FLAG_DATA_OUT_WAITEOSP         BIT(11)
+
+#define P54_HDR_FLAG_DATA_IN_FCS_GOOD          BIT(0)
+#define P54_HDR_FLAG_DATA_IN_MATCH_MAC         BIT(1)
+#define P54_HDR_FLAG_DATA_IN_MCBC              BIT(2)
+#define P54_HDR_FLAG_DATA_IN_BEACON            BIT(3)
+#define P54_HDR_FLAG_DATA_IN_MATCH_BSS         BIT(4)
+#define P54_HDR_FLAG_DATA_IN_BCAST_BSS         BIT(5)
+#define P54_HDR_FLAG_DATA_IN_DATA              BIT(6)
+#define P54_HDR_FLAG_DATA_IN_TRUNCATED         BIT(7)
+#define P54_HDR_FLAG_DATA_IN_BIT8              BIT(8)
+#define P54_HDR_FLAG_DATA_IN_TRANSPARENT       BIT(9)
+
+struct p54_hdr {
+       __le16 flags;
+       __le16 len;
+       __le32 req_id;
+       __le16 type;    /* enum p54_control_frame_types */
+       u8 rts_tries;
+       u8 tries;
+       u8 data[0];
+} __packed;
+
+#define GET_REQ_ID(skb)                                                        \
+       (((struct p54_hdr *) ((struct sk_buff *) skb)->data)->req_id)   \
+
+#define FREE_AFTER_TX(skb)                                             \
+       ((((struct p54_hdr *) ((struct sk_buff *) skb)->data)->         \
+       flags) == cpu_to_le16(P54_HDR_FLAG_CONTROL_OPSET))
+
+#define IS_DATA_FRAME(skb)                                             \
+       (!((((struct p54_hdr *) ((struct sk_buff *) skb)->data)->       \
+       flags) & cpu_to_le16(P54_HDR_FLAG_CONTROL)))
+
+/*
+ * shared interface ID definitions
+ * The interface ID is a unique identification of a specific interface.
+ * The following values are reserved: 0x0000, 0x0002, 0x0012, 0x0014, 0x0015
+ */
+#define IF_ID_ISL36356A                        0x0001  /* ISL36356A <-> Firmware */
+#define IF_ID_MVC                      0x0003  /* MAC Virtual Coprocessor */
+#define IF_ID_DEBUG                    0x0008  /* PolDebug Interface */
+#define IF_ID_PRODUCT                  0x0009
+#define IF_ID_OEM                      0x000a
+#define IF_ID_PCI3877                  0x000b  /* 3877 <-> Host PCI */
+#define IF_ID_ISL37704C                        0x000c  /* ISL37704C <-> Fw */
+#define IF_ID_ISL39000                 0x000f  /* ISL39000 <-> Fw */
+#define IF_ID_ISL39300A                        0x0010  /* ISL39300A <-> Fw */
+#define IF_ID_ISL37700_UAP             0x0016  /* ISL37700 uAP Fw <-> Fw */
+#define IF_ID_ISL39000_UAP             0x0017  /* ISL39000 uAP Fw <-> Fw */
+#define IF_ID_LMAC                     0x001a  /* Interface exposed by LMAC */
+
+struct exp_if {
+       __le16 role;
+       __le16 if_id;
+       __le16 variant;
+       __le16 btm_compat;
+       __le16 top_compat;
+} __packed;
+
+struct dep_if {
+       __le16 role;
+       __le16 if_id;
+       __le16 variant;
+} __packed;
+
+/* driver <-> lmac definitions */
+struct p54_eeprom_lm86 {
+       union {
+               struct {
+                       __le16 offset;
+                       __le16 len;
+                       u8 data[0];
+               } __packed v1;
+               struct {
+                       __le32 offset;
+                       __le16 len;
+                       u8 magic2;
+                       u8 pad;
+                       u8 magic[4];
+                       u8 data[0];
+               } __packed v2;
+       }  __packed;
+} __packed;
+
+enum p54_rx_decrypt_status {
+       P54_DECRYPT_NONE = 0,
+       P54_DECRYPT_OK,
+       P54_DECRYPT_NOKEY,
+       P54_DECRYPT_NOMICHAEL,
+       P54_DECRYPT_NOCKIPMIC,
+       P54_DECRYPT_FAIL_WEP,
+       P54_DECRYPT_FAIL_TKIP,
+       P54_DECRYPT_FAIL_MICHAEL,
+       P54_DECRYPT_FAIL_CKIPKP,
+       P54_DECRYPT_FAIL_CKIPMIC,
+       P54_DECRYPT_FAIL_AESCCMP
+};
+
+struct p54_rx_data {
+       __le16 flags;
+       __le16 len;
+       __le16 freq;
+       u8 antenna;
+       u8 rate;
+       u8 rssi;
+       u8 quality;
+       u8 decrypt_status;
+       u8 rssi_raw;
+       __le32 tsf32;
+       __le32 unalloc0;
+       u8 align[0];
+} __packed;
+
+enum p54_trap_type {
+       P54_TRAP_SCAN = 0,
+       P54_TRAP_TIMER,
+       P54_TRAP_BEACON_TX,
+       P54_TRAP_FAA_RADIO_ON,
+       P54_TRAP_FAA_RADIO_OFF,
+       P54_TRAP_RADAR,
+       P54_TRAP_NO_BEACON,
+       P54_TRAP_TBTT,
+       P54_TRAP_SCO_ENTER,
+       P54_TRAP_SCO_EXIT
+};
+
+struct p54_trap {
+       __le16 event;
+       __le16 frequency;
+} __packed;
+
+enum p54_frame_sent_status {
+       P54_TX_OK = 0,
+       P54_TX_FAILED,
+       P54_TX_PSM,
+       P54_TX_PSM_CANCELLED = 4
+};
+
+struct p54_frame_sent {
+       u8 status;
+       u8 tries;
+       u8 ack_rssi;
+       u8 quality;
+       __le16 seq;
+       u8 antenna;
+       u8 padding;
+} __packed;
+
+enum p54_tx_data_crypt {
+       P54_CRYPTO_NONE = 0,
+       P54_CRYPTO_WEP,
+       P54_CRYPTO_TKIP,
+       P54_CRYPTO_TKIPMICHAEL,
+       P54_CRYPTO_CCX_WEPMIC,
+       P54_CRYPTO_CCX_KPMIC,
+       P54_CRYPTO_CCX_KP,
+       P54_CRYPTO_AESCCMP
+};
+
+enum p54_tx_data_queue {
+       P54_QUEUE_BEACON        = 0,
+       P54_QUEUE_FWSCAN        = 1,
+       P54_QUEUE_MGMT          = 2,
+       P54_QUEUE_CAB           = 3,
+       P54_QUEUE_DATA          = 4,
+
+       P54_QUEUE_AC_NUM        = 4,
+       P54_QUEUE_AC_VO         = 4,
+       P54_QUEUE_AC_VI         = 5,
+       P54_QUEUE_AC_BE         = 6,
+       P54_QUEUE_AC_BK         = 7,
+
+       /* keep last */
+       P54_QUEUE_NUM           = 8,
+};
+
+#define IS_QOS_QUEUE(n)        (n >= P54_QUEUE_DATA)
+
+struct p54_tx_data {
+       u8 rateset[8];
+       u8 rts_rate_idx;
+       u8 crypt_offset;
+       u8 key_type;
+       u8 key_len;
+       u8 key[16];
+       u8 hw_queue;
+       u8 backlog;
+       __le16 durations[4];
+       u8 tx_antenna;
+       union {
+               struct {
+                       u8 cts_rate;
+                       __le16 output_power;
+               } __packed longbow;
+               struct {
+                       u8 output_power;
+                       u8 cts_rate;
+                       u8 unalloc;
+               } __packed normal;
+       } __packed;
+       u8 unalloc2[2];
+       u8 align[0];
+} __packed;
+
+/* unit is ms */
+#define P54_TX_FRAME_LIFETIME 2000
+#define P54_TX_TIMEOUT 4000
+#define P54_STATISTICS_UPDATE 5000
+
+#define P54_FILTER_TYPE_NONE           0
+#define P54_FILTER_TYPE_STATION                BIT(0)
+#define P54_FILTER_TYPE_IBSS           BIT(1)
+#define P54_FILTER_TYPE_AP             BIT(2)
+#define P54_FILTER_TYPE_TRANSPARENT    BIT(3)
+#define P54_FILTER_TYPE_PROMISCUOUS    BIT(4)
+#define P54_FILTER_TYPE_HIBERNATE      BIT(5)
+#define P54_FILTER_TYPE_NOACK          BIT(6)
+#define P54_FILTER_TYPE_RX_DISABLED    BIT(7)
+
+struct p54_setup_mac {
+       __le16 mac_mode;
+       u8 mac_addr[ETH_ALEN];
+       u8 bssid[ETH_ALEN];
+       u8 rx_antenna;
+       u8 rx_align;
+       union {
+               struct {
+                       __le32 basic_rate_mask;
+                       u8 rts_rates[8];
+                       __le32 rx_addr;
+                       __le16 max_rx;
+                       __le16 rxhw;
+                       __le16 wakeup_timer;
+                       __le16 unalloc0;
+               } __packed v1;
+               struct {
+                       __le32 rx_addr;
+                       __le16 max_rx;
+                       __le16 rxhw;
+                       __le16 timer;
+                       __le16 truncate;
+                       __le32 basic_rate_mask;
+                       u8 sbss_offset;
+                       u8 mcast_window;
+                       u8 rx_rssi_threshold;
+                       u8 rx_ed_threshold;
+                       __le32 ref_clock;
+                       __le16 lpf_bandwidth;
+                       __le16 osc_start_delay;
+               } __packed v2;
+       } __packed;
+} __packed;
+
+#define P54_SETUP_V1_LEN 40
+#define P54_SETUP_V2_LEN (sizeof(struct p54_setup_mac))
+
+#define P54_SCAN_EXIT  BIT(0)
+#define P54_SCAN_TRAP  BIT(1)
+#define P54_SCAN_ACTIVE BIT(2)
+#define P54_SCAN_FILTER BIT(3)
+
+struct p54_scan_head {
+       __le16 mode;
+       __le16 dwell;
+       u8 scan_params[20];
+       __le16 freq;
+} __packed;
+
+struct p54_pa_curve_data_sample {
+       u8 rf_power;
+       u8 pa_detector;
+       u8 data_barker;
+       u8 data_bpsk;
+       u8 data_qpsk;
+       u8 data_16qam;
+       u8 data_64qam;
+       u8 padding;
+} __packed;
+
+struct p54_scan_body {
+       u8 pa_points_per_curve;
+       u8 val_barker;
+       u8 val_bpsk;
+       u8 val_qpsk;
+       u8 val_16qam;
+       u8 val_64qam;
+       struct p54_pa_curve_data_sample curve_data[8];
+       u8 dup_bpsk;
+       u8 dup_qpsk;
+       u8 dup_16qam;
+       u8 dup_64qam;
+} __packed;
+
+/*
+ * Warning: Longbow's structures are bogus.
+ */
+struct p54_channel_output_limit_longbow {
+       __le16 rf_power_points[12];
+} __packed;
+
+struct p54_pa_curve_data_sample_longbow {
+       __le16 rf_power;
+       __le16 pa_detector;
+       struct {
+               __le16 data[4];
+       } points[3] __packed;
+} __packed;
+
+struct p54_scan_body_longbow {
+       struct p54_channel_output_limit_longbow power_limits;
+       struct p54_pa_curve_data_sample_longbow curve_data[8];
+       __le16 unkn[6];         /* maybe more power_limits or rate_mask */
+} __packed;
+
+union p54_scan_body_union {
+       struct p54_scan_body normal;
+       struct p54_scan_body_longbow longbow;
+} __packed;
+
+struct p54_scan_tail_rate {
+       __le32 basic_rate_mask;
+       u8 rts_rates[8];
+} __packed;
+
+struct p54_led {
+       __le16 flags;
+       __le16 mask[2];
+       __le16 delay[2];
+} __packed;
+
+struct p54_edcf {
+       u8 flags;
+       u8 slottime;
+       u8 sifs;
+       u8 eofpad;
+       struct p54_edcf_queue_param queue[8];
+       u8 mapping[4];
+       __le16 frameburst;
+       __le16 round_trip_delay;
+} __packed;
+
+struct p54_statistics {
+       __le32 rx_success;
+       __le32 rx_bad_fcs;
+       __le32 rx_abort;
+       __le32 rx_abort_phy;
+       __le32 rts_success;
+       __le32 rts_fail;
+       __le32 tsf32;
+       __le32 airtime;
+       __le32 noise;
+       __le32 sample_noise[8];
+       __le32 sample_cca;
+       __le32 sample_tx;
+} __packed;
+
+struct p54_xbow_synth {
+       __le16 magic1;
+       __le16 magic2;
+       __le16 freq;
+       u32 padding[5];
+} __packed;
+
+struct p54_timer {
+       __le32 interval;
+} __packed;
+
+struct p54_keycache {
+       u8 entry;
+       u8 key_id;
+       u8 mac[ETH_ALEN];
+       u8 padding[2];
+       u8 key_type;
+       u8 key_len;
+       u8 key[24];
+} __packed;
+
+struct p54_burst {
+       u8 flags;
+       u8 queue;
+       u8 backlog;
+       u8 pad;
+       __le16 durations[32];
+} __packed;
+
+struct p54_psm_interval {
+       __le16 interval;
+       __le16 periods;
+} __packed;
+
+#define P54_PSM_CAM                    0
+#define P54_PSM                                BIT(0)
+#define P54_PSM_DTIM                   BIT(1)
+#define P54_PSM_MCBC                   BIT(2)
+#define P54_PSM_CHECKSUM               BIT(3)
+#define P54_PSM_SKIP_MORE_DATA         BIT(4)
+#define P54_PSM_BEACON_TIMEOUT         BIT(5)
+#define P54_PSM_HFOSLEEP               BIT(6)
+#define P54_PSM_AUTOSWITCH_SLEEP       BIT(7)
+#define P54_PSM_LPIT                   BIT(8)
+#define P54_PSM_BF_UCAST_SKIP          BIT(9)
+#define P54_PSM_BF_MCAST_SKIP          BIT(10)
+
+struct p54_psm {
+       __le16 mode;
+       __le16 aid;
+       struct p54_psm_interval intervals[4];
+       u8 beacon_rssi_skip_max;
+       u8 rssi_delta_threshold;
+       u8 nr;
+       u8 exclude[1];
+} __packed;
+
+#define MC_FILTER_ADDRESS_NUM 4
+
+struct p54_group_address_table {
+       __le16 filter_enable;
+       __le16 num_address;
+       u8 mac_list[MC_FILTER_ADDRESS_NUM][ETH_ALEN];
+} __packed;
+
+struct p54_txcancel {
+       __le32 req_id;
+} __packed;
+
+struct p54_sta_unlock {
+       u8 addr[ETH_ALEN];
+       u16 padding;
+} __packed;
+
+#define P54_TIM_CLEAR BIT(15)
+struct p54_tim {
+       u8 count;
+       u8 padding[3];
+       __le16 entry[8];
+} __packed;
+
+struct p54_cce_quiet {
+       __le32 period;
+} __packed;
+
+struct p54_bt_balancer {
+       __le16 prio_thresh;
+       __le16 acl_thresh;
+} __packed;
+
+struct p54_arp_table {
+       __le16 filter_enable;
+       u8 ipv4_addr[4];
+} __packed;
+
+/* LED control */
+int p54_set_leds(struct p54_common *priv);
+int p54_init_leds(struct p54_common *priv);
+void p54_unregister_leds(struct p54_common *priv);
+
+/* xmit functions */
+int p54_tx_80211(struct ieee80211_hw *dev, struct sk_buff *skb);
+int p54_tx_cancel(struct p54_common *priv, __le32 req_id);
+void p54_tx(struct p54_common *priv, struct sk_buff *skb);
+
+/* synth/phy configuration */
+int p54_init_xbow_synth(struct p54_common *priv);
+int p54_scan(struct p54_common *priv, u16 mode, u16 dwell);
+
+/* MAC */
+int p54_sta_unlock(struct p54_common *priv, u8 *addr);
+int p54_update_beacon_tim(struct p54_common *priv, u16 aid, bool set);
+int p54_setup_mac(struct p54_common *priv);
+int p54_set_ps(struct p54_common *priv);
+int p54_fetch_statistics(struct p54_common *priv);
+
+/* e/v DCF setup */
+int p54_set_edcf(struct p54_common *priv);
+
+/* cryptographic engine */
+int p54_upload_key(struct p54_common *priv, u8 algo, int slot,
+                  u8 idx, u8 len, u8 *addr, u8* key);
+
+/* eeprom */
+int p54_download_eeprom(struct p54_common *priv, void *buf,
+                       u16 offset, u16 len);
+
+#endif /* LMAC_H */
diff --git a/drivers/net/wireless/p54/main.c b/drivers/net/wireless/p54/main.c
new file mode 100644 (file)
index 0000000..f9b4f6a
--- /dev/null
@@ -0,0 +1,607 @@
+/*
+ * mac80211 glue code for mac80211 Prism54 drivers
+ *
+ * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
+ * Copyright (c) 2007-2009, Christian Lamparter <chunkeey@web.de>
+ * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
+ *
+ * Based on:
+ * - the islsm (softmac prism54) driver, which is:
+ *   Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
+ * - stlc45xx driver
+ *   Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/firmware.h>
+#include <linux/etherdevice.h>
+
+#include <net/mac80211.h>
+
+#include "p54.h"
+#include "lmac.h"
+
+static int modparam_nohwcrypt;
+module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO);
+MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");
+MODULE_AUTHOR("Michael Wu <flamingice@sourmilk.net>");
+MODULE_DESCRIPTION("Softmac Prism54 common code");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("prism54common");
+
+static void p54_sta_notify(struct ieee80211_hw *dev, struct ieee80211_vif *vif,
+                             enum sta_notify_cmd notify_cmd,
+                             struct ieee80211_sta *sta)
+{
+       struct p54_common *priv = dev->priv;
+       switch (notify_cmd) {
+       case STA_NOTIFY_ADD:
+       case STA_NOTIFY_REMOVE:
+               /*
+                * Notify the firmware that we don't want or we don't
+                * need to buffer frames for this station anymore.
+                */
+
+               p54_sta_unlock(priv, sta->addr);
+               break;
+       case STA_NOTIFY_AWAKE:
+               /* update the firmware's filter table */
+               p54_sta_unlock(priv, sta->addr);
+               break;
+       default:
+               break;
+       }
+}
+
+static int p54_set_tim(struct ieee80211_hw *dev, struct ieee80211_sta *sta,
+                       bool set)
+{
+       struct p54_common *priv = dev->priv;
+
+       return p54_update_beacon_tim(priv, sta->aid, set);
+}
+
+static int p54_beacon_format_ie_tim(struct sk_buff *skb)
+{
+       /*
+        * the good excuse for this mess is ... the firmware.
+        * The dummy TIM MUST be at the end of the beacon frame,
+        * because it'll be overwritten!
+        */
+
+       struct ieee80211_mgmt *mgmt = (void *)skb->data;
+       u8 *pos, *end;
+
+       if (skb->len <= sizeof(mgmt))
+               return -EINVAL;
+
+       pos = (u8 *)mgmt->u.beacon.variable;
+       end = skb->data + skb->len;
+       while (pos < end) {
+               if (pos + 2 + pos[1] > end)
+                       return -EINVAL;
+
+               if (pos[0] == WLAN_EID_TIM) {
+                       u8 dtim_len = pos[1];
+                       u8 dtim_period = pos[3];
+                       u8 *next = pos + 2 + dtim_len;
+
+                       if (dtim_len < 3)
+                               return -EINVAL;
+
+                       memmove(pos, next, end - next);
+
+                       if (dtim_len > 3)
+                               skb_trim(skb, skb->len - (dtim_len - 3));
+
+                       pos = end - (dtim_len + 2);
+
+                       /* add the dummy at the end */
+                       pos[0] = WLAN_EID_TIM;
+                       pos[1] = 3;
+                       pos[2] = 0;
+                       pos[3] = dtim_period;
+                       pos[4] = 0;
+                       return 0;
+               }
+               pos += 2 + pos[1];
+       }
+       return 0;
+}
+
+static int p54_beacon_update(struct p54_common *priv,
+                       struct ieee80211_vif *vif)
+{
+       struct sk_buff *beacon;
+       __le32 old_beacon_req_id;
+       int ret;
+
+       beacon = ieee80211_beacon_get(priv->hw, vif);
+       if (!beacon)
+               return -ENOMEM;
+       ret = p54_beacon_format_ie_tim(beacon);
+       if (ret)
+               return ret;
+
+       old_beacon_req_id = priv->beacon_req_id;
+       priv->beacon_req_id = GET_REQ_ID(beacon);
+
+       ret = p54_tx_80211(priv->hw, beacon);
+       if (ret) {
+               priv->beacon_req_id = old_beacon_req_id;
+               return -ENOSPC;
+       }
+
+       priv->tsf_high32 = 0;
+       priv->tsf_low32 = 0;
+
+       return 0;
+}
+
+static int p54_start(struct ieee80211_hw *dev)
+{
+       struct p54_common *priv = dev->priv;
+       int err;
+
+       mutex_lock(&priv->conf_mutex);
+       err = priv->open(dev);
+       if (err)
+               goto out;
+       P54_SET_QUEUE(priv->qos_params[0], 0x0002, 0x0003, 0x0007, 47);
+       P54_SET_QUEUE(priv->qos_params[1], 0x0002, 0x0007, 0x000f, 94);
+       P54_SET_QUEUE(priv->qos_params[2], 0x0003, 0x000f, 0x03ff, 0);
+       P54_SET_QUEUE(priv->qos_params[3], 0x0007, 0x000f, 0x03ff, 0);
+       err = p54_set_edcf(priv);
+       if (err)
+               goto out;
+
+       memset(priv->bssid, ~0, ETH_ALEN);
+       priv->mode = NL80211_IFTYPE_MONITOR;
+       err = p54_setup_mac(priv);
+       if (err) {
+               priv->mode = NL80211_IFTYPE_UNSPECIFIED;
+               goto out;
+       }
+
+       queue_delayed_work(dev->workqueue, &priv->work, 0);
+
+       priv->softled_state = 0;
+       err = p54_set_leds(priv);
+
+out:
+       mutex_unlock(&priv->conf_mutex);
+       return err;
+}
+
+static void p54_stop(struct ieee80211_hw *dev)
+{
+       struct p54_common *priv = dev->priv;
+       int i;
+
+       mutex_lock(&priv->conf_mutex);
+       priv->mode = NL80211_IFTYPE_UNSPECIFIED;
+       priv->softled_state = 0;
+       p54_set_leds(priv);
+
+       cancel_delayed_work_sync(&priv->work);
+
+       priv->stop(dev);
+       skb_queue_purge(&priv->tx_pending);
+       skb_queue_purge(&priv->tx_queue);
+       for (i = 0; i < P54_QUEUE_NUM; i++) {
+               priv->tx_stats[i].count = 0;
+               priv->tx_stats[i].len = 0;
+       }
+
+       priv->beacon_req_id = cpu_to_le32(0);
+       priv->tsf_high32 = priv->tsf_low32 = 0;
+       mutex_unlock(&priv->conf_mutex);
+}
+
+static int p54_add_interface(struct ieee80211_hw *dev,
+                            struct ieee80211_if_init_conf *conf)
+{
+       struct p54_common *priv = dev->priv;
+
+       mutex_lock(&priv->conf_mutex);
+       if (priv->mode != NL80211_IFTYPE_MONITOR) {
+               mutex_unlock(&priv->conf_mutex);
+               return -EOPNOTSUPP;
+       }
+
+       priv->vif = conf->vif;
+
+       switch (conf->type) {
+       case NL80211_IFTYPE_STATION:
+       case NL80211_IFTYPE_ADHOC:
+       case NL80211_IFTYPE_AP:
+       case NL80211_IFTYPE_MESH_POINT:
+               priv->mode = conf->type;
+               break;
+       default:
+               mutex_unlock(&priv->conf_mutex);
+               return -EOPNOTSUPP;
+       }
+
+       memcpy(priv->mac_addr, conf->mac_addr, ETH_ALEN);
+       p54_setup_mac(priv);
+       mutex_unlock(&priv->conf_mutex);
+       return 0;
+}
+
+static void p54_remove_interface(struct ieee80211_hw *dev,
+                                struct ieee80211_if_init_conf *conf)
+{
+       struct p54_common *priv = dev->priv;
+
+       mutex_lock(&priv->conf_mutex);
+       priv->vif = NULL;
+       if (priv->beacon_req_id) {
+               p54_tx_cancel(priv, priv->beacon_req_id);
+               priv->beacon_req_id = cpu_to_le32(0);
+       }
+       priv->mode = NL80211_IFTYPE_MONITOR;
+       memset(priv->mac_addr, 0, ETH_ALEN);
+       memset(priv->bssid, 0, ETH_ALEN);
+       p54_setup_mac(priv);
+       mutex_unlock(&priv->conf_mutex);
+}
+
+static int p54_config(struct ieee80211_hw *dev, u32 changed)
+{
+       int ret = 0;
+       struct p54_common *priv = dev->priv;
+       struct ieee80211_conf *conf = &dev->conf;
+
+       mutex_lock(&priv->conf_mutex);
+       if (changed & IEEE80211_CONF_CHANGE_POWER)
+               priv->output_power = conf->power_level << 2;
+       if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
+               ret = p54_scan(priv, P54_SCAN_EXIT, 0);
+               if (ret)
+                       goto out;
+       }
+       if (changed & IEEE80211_CONF_CHANGE_PS) {
+               ret = p54_set_ps(priv);
+               if (ret)
+                       goto out;
+       }
+
+out:
+       mutex_unlock(&priv->conf_mutex);
+       return ret;
+}
+
+static void p54_configure_filter(struct ieee80211_hw *dev,
+                                unsigned int changed_flags,
+                                unsigned int *total_flags,
+                                int mc_count, struct dev_mc_list *mclist)
+{
+       struct p54_common *priv = dev->priv;
+
+       *total_flags &= FIF_PROMISC_IN_BSS |
+                       FIF_OTHER_BSS;
+
+       priv->filter_flags = *total_flags;
+
+       if (changed_flags & (FIF_PROMISC_IN_BSS | FIF_OTHER_BSS))
+               p54_setup_mac(priv);
+}
+
+static int p54_conf_tx(struct ieee80211_hw *dev, u16 queue,
+                      const struct ieee80211_tx_queue_params *params)
+{
+       struct p54_common *priv = dev->priv;
+       int ret;
+
+       mutex_lock(&priv->conf_mutex);
+       if ((params) && !(queue > 4)) {
+               P54_SET_QUEUE(priv->qos_params[queue], params->aifs,
+                       params->cw_min, params->cw_max, params->txop);
+               ret = p54_set_edcf(priv);
+       } else
+               ret = -EINVAL;
+       mutex_unlock(&priv->conf_mutex);
+       return ret;
+}
+
+static void p54_work(struct work_struct *work)
+{
+       struct p54_common *priv = container_of(work, struct p54_common,
+                                              work.work);
+
+       if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED))
+               return ;
+
+       /*
+        * TODO: walk through tx_queue and do the following tasks
+        *      1. initiate bursts.
+        *      2. cancel stuck frames / reset the device if necessary.
+        */
+
+       p54_fetch_statistics(priv);
+}
+
+static int p54_get_stats(struct ieee80211_hw *dev,
+                        struct ieee80211_low_level_stats *stats)
+{
+       struct p54_common *priv = dev->priv;
+
+       memcpy(stats, &priv->stats, sizeof(*stats));
+       return 0;
+}
+
+static int p54_get_tx_stats(struct ieee80211_hw *dev,
+                           struct ieee80211_tx_queue_stats *stats)
+{
+       struct p54_common *priv = dev->priv;
+
+       memcpy(stats, &priv->tx_stats[P54_QUEUE_DATA],
+              sizeof(stats[0]) * dev->queues);
+       return 0;
+}
+
+static void p54_bss_info_changed(struct ieee80211_hw *dev,
+                                struct ieee80211_vif *vif,
+                                struct ieee80211_bss_conf *info,
+                                u32 changed)
+{
+       struct p54_common *priv = dev->priv;
+
+       mutex_lock(&priv->conf_mutex);
+       if (changed & BSS_CHANGED_BSSID) {
+               memcpy(priv->bssid, info->bssid, ETH_ALEN);
+               p54_setup_mac(priv);
+       }
+
+       if (changed & BSS_CHANGED_BEACON) {
+               p54_scan(priv, P54_SCAN_EXIT, 0);
+               p54_setup_mac(priv);
+               p54_beacon_update(priv, vif);
+               p54_set_edcf(priv);
+       }
+
+       if (changed & (BSS_CHANGED_ERP_SLOT | BSS_CHANGED_BEACON)) {
+               priv->use_short_slot = info->use_short_slot;
+               p54_set_edcf(priv);
+       }
+       if (changed & BSS_CHANGED_BASIC_RATES) {
+               if (dev->conf.channel->band == IEEE80211_BAND_5GHZ)
+                       priv->basic_rate_mask = (info->basic_rates << 4);
+               else
+                       priv->basic_rate_mask = info->basic_rates;
+               p54_setup_mac(priv);
+               if (priv->fw_var >= 0x500)
+                       p54_scan(priv, P54_SCAN_EXIT, 0);
+       }
+       if (changed & BSS_CHANGED_ASSOC) {
+               if (info->assoc) {
+                       priv->aid = info->aid;
+                       priv->wakeup_timer = info->beacon_int *
+                                            info->dtim_period * 5;
+                       p54_setup_mac(priv);
+               }
+       }
+
+       mutex_unlock(&priv->conf_mutex);
+}
+
+static int p54_set_key(struct ieee80211_hw *dev, enum set_key_cmd cmd,
+                      struct ieee80211_vif *vif, struct ieee80211_sta *sta,
+                      struct ieee80211_key_conf *key)
+{
+       struct p54_common *priv = dev->priv;
+       int slot, ret = 0;
+       u8 algo = 0;
+       u8 *addr = NULL;
+
+       if (modparam_nohwcrypt)
+               return -EOPNOTSUPP;
+
+       mutex_lock(&priv->conf_mutex);
+       if (cmd == SET_KEY) {
+               switch (key->alg) {
+               case ALG_TKIP:
+                       if (!(priv->privacy_caps & (BR_DESC_PRIV_CAP_MICHAEL |
+                             BR_DESC_PRIV_CAP_TKIP))) {
+                               ret = -EOPNOTSUPP;
+                               goto out_unlock;
+                       }
+                       key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
+                       algo = P54_CRYPTO_TKIPMICHAEL;
+                       break;
+               case ALG_WEP:
+                       if (!(priv->privacy_caps & BR_DESC_PRIV_CAP_WEP)) {
+                               ret = -EOPNOTSUPP;
+                               goto out_unlock;
+                       }
+                       key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
+                       algo = P54_CRYPTO_WEP;
+                       break;
+               case ALG_CCMP:
+                       if (!(priv->privacy_caps & BR_DESC_PRIV_CAP_AESCCMP)) {
+                               ret = -EOPNOTSUPP;
+                               goto out_unlock;
+                       }
+                       key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
+                       algo = P54_CRYPTO_AESCCMP;
+                       break;
+               default:
+                       ret = -EOPNOTSUPP;
+                       goto out_unlock;
+               }
+               slot = bitmap_find_free_region(priv->used_rxkeys,
+                                              priv->rx_keycache_size, 0);
+
+               if (slot < 0) {
+                       /*
+                        * The device supports the choosen algorithm, but the
+                        * firmware does not provide enough key slots to store
+                        * all of them.
+                        * But encryption offload for outgoing frames is always
+                        * possible, so we just pretend that the upload was
+                        * successful and do the decryption in software.
+                        */
+
+                       /* mark the key as invalid. */
+                       key->hw_key_idx = 0xff;
+                       goto out_unlock;
+               }
+       } else {
+               slot = key->hw_key_idx;
+
+               if (slot == 0xff) {
+                       /* This key was not uploaded into the rx key cache. */
+
+                       goto out_unlock;
+               }
+
+               bitmap_release_region(priv->used_rxkeys, slot, 0);
+               algo = 0;
+       }
+
+       if (sta)
+               addr = sta->addr;
+
+       ret = p54_upload_key(priv, algo, slot, key->keyidx,
+                            key->keylen, addr, key->key);
+       if (ret) {
+               bitmap_release_region(priv->used_rxkeys, slot, 0);
+               ret = -EOPNOTSUPP;
+               goto out_unlock;
+       }
+
+       key->hw_key_idx = slot;
+
+out_unlock:
+       mutex_unlock(&priv->conf_mutex);
+       return ret;
+}
+
+static const struct ieee80211_ops p54_ops = {
+       .tx                     = p54_tx_80211,
+       .start                  = p54_start,
+       .stop                   = p54_stop,
+       .add_interface          = p54_add_interface,
+       .remove_interface       = p54_remove_interface,
+       .set_tim                = p54_set_tim,
+       .sta_notify             = p54_sta_notify,
+       .set_key                = p54_set_key,
+       .config                 = p54_config,
+       .bss_info_changed       = p54_bss_info_changed,
+       .configure_filter       = p54_configure_filter,
+       .conf_tx                = p54_conf_tx,
+       .get_stats              = p54_get_stats,
+       .get_tx_stats           = p54_get_tx_stats
+};
+
+struct ieee80211_hw *p54_init_common(size_t priv_data_len)
+{
+       struct ieee80211_hw *dev;
+       struct p54_common *priv;
+
+       dev = ieee80211_alloc_hw(priv_data_len, &p54_ops);
+       if (!dev)
+               return NULL;
+
+       priv = dev->priv;
+       priv->hw = dev;
+       priv->mode = NL80211_IFTYPE_UNSPECIFIED;
+       priv->basic_rate_mask = 0x15f;
+       spin_lock_init(&priv->tx_stats_lock);
+       skb_queue_head_init(&priv->tx_queue);
+       skb_queue_head_init(&priv->tx_pending);
+       dev->flags = IEEE80211_HW_RX_INCLUDES_FCS |
+                    IEEE80211_HW_SIGNAL_DBM |
+                    IEEE80211_HW_NOISE_DBM;
+
+       dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
+                                     BIT(NL80211_IFTYPE_ADHOC) |
+                                     BIT(NL80211_IFTYPE_AP) |
+                                     BIT(NL80211_IFTYPE_MESH_POINT);
+
+       dev->channel_change_time = 1000;        /* TODO: find actual value */
+       priv->tx_stats[P54_QUEUE_BEACON].limit = 1;
+       priv->tx_stats[P54_QUEUE_FWSCAN].limit = 1;
+       priv->tx_stats[P54_QUEUE_MGMT].limit = 3;
+       priv->tx_stats[P54_QUEUE_CAB].limit = 3;
+       priv->tx_stats[P54_QUEUE_DATA].limit = 5;
+       dev->queues = 1;
+       priv->noise = -94;
+       /*
+        * We support at most 8 tries no matter which rate they're at,
+        * we cannot support max_rates * max_rate_tries as we set it
+        * here, but setting it correctly to 4/2 or so would limit us
+        * artificially if the RC algorithm wants just two rates, so
+        * let's say 4/7, we'll redistribute it at TX time, see the
+        * comments there.
+        */
+       dev->max_rates = 4;
+       dev->max_rate_tries = 7;
+       dev->extra_tx_headroom = sizeof(struct p54_hdr) + 4 +
+                                sizeof(struct p54_tx_data);
+
+       mutex_init(&priv->conf_mutex);
+       mutex_init(&priv->eeprom_mutex);
+       init_completion(&priv->eeprom_comp);
+       INIT_DELAYED_WORK(&priv->work, p54_work);
+
+       return dev;
+}
+EXPORT_SYMBOL_GPL(p54_init_common);
+
+int p54_register_common(struct ieee80211_hw *dev, struct device *pdev)
+{
+       struct p54_common *priv = dev->priv;
+       int err;
+
+       err = ieee80211_register_hw(dev);
+       if (err) {
+               dev_err(pdev, "Cannot register device (%d).\n", err);
+               return err;
+       }
+
+#ifdef CONFIG_P54_LEDS
+       err = p54_init_leds(priv);
+       if (err)
+               return err;
+#endif /* CONFIG_P54_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);
+       kfree(priv->used_rxkeys);
+       priv->iq_autocal = NULL;
+       priv->output_limit = NULL;
+       priv->curve_data = NULL;
+       priv->used_rxkeys = NULL;
+       ieee80211_free_hw(dev);
+}
+EXPORT_SYMBOL_GPL(p54_free_common);
+
+void p54_unregister_common(struct ieee80211_hw *dev)
+{
+       struct p54_common *priv = dev->priv;
+
+#ifdef CONFIG_P54_LEDS
+       p54_unregister_leds(priv);
+#endif /* CONFIG_P54_LEDS */
+
+       ieee80211_unregister_hw(dev);
+       mutex_destroy(&priv->conf_mutex);
+       mutex_destroy(&priv->eeprom_mutex);
+}
+EXPORT_SYMBOL_GPL(p54_unregister_common);
index db3df94..19d085c 100644 (file)
@@ -1,6 +1,3 @@
-#ifndef P54_H
-#define P54_H
-
 /*
  * Shared defines for all mac80211 Prism54 code
  *
  * published by the Free Software Foundation.
  */
 
+#ifndef P54_H
+#define P54_H
+
 #ifdef CONFIG_P54_LEDS
 #include <linux/leds.h>
 #endif /* CONFIG_P54_LEDS */
 
-enum p54_control_frame_types {
-       P54_CONTROL_TYPE_SETUP = 0,
-       P54_CONTROL_TYPE_SCAN,
-       P54_CONTROL_TYPE_TRAP,
-       P54_CONTROL_TYPE_DCFINIT,
-       P54_CONTROL_TYPE_RX_KEYCACHE,
-       P54_CONTROL_TYPE_TIM,
-       P54_CONTROL_TYPE_PSM,
-       P54_CONTROL_TYPE_TXCANCEL,
-       P54_CONTROL_TYPE_TXDONE,
-       P54_CONTROL_TYPE_BURST,
-       P54_CONTROL_TYPE_STAT_READBACK,
-       P54_CONTROL_TYPE_BBP,
-       P54_CONTROL_TYPE_EEPROM_READBACK,
-       P54_CONTROL_TYPE_LED,
-       P54_CONTROL_TYPE_GPIO,
-       P54_CONTROL_TYPE_TIMER,
-       P54_CONTROL_TYPE_MODULATION,
-       P54_CONTROL_TYPE_SYNTH_CONFIG,
-       P54_CONTROL_TYPE_DETECTOR_VALUE,
-       P54_CONTROL_TYPE_XBOW_SYNTH_CFG,
-       P54_CONTROL_TYPE_CCE_QUIET,
-       P54_CONTROL_TYPE_PSM_STA_UNLOCK,
-       P54_CONTROL_TYPE_PCS,
-       P54_CONTROL_TYPE_BT_BALANCER = 28,
-       P54_CONTROL_TYPE_GROUP_ADDRESS_TABLE = 30,
-       P54_CONTROL_TYPE_ARPTABLE = 31,
-       P54_CONTROL_TYPE_BT_OPTIONS = 35
-};
+#define ISL38XX_DEV_FIRMWARE_ADDR 0x20000
+
+#define BR_CODE_MIN                    0x80000000
+#define BR_CODE_COMPONENT_ID           0x80000001
+#define BR_CODE_COMPONENT_VERSION      0x80000002
+#define BR_CODE_DEPENDENT_IF           0x80000003
+#define BR_CODE_EXPOSED_IF             0x80000004
+#define BR_CODE_DESCR                  0x80000101
+#define BR_CODE_MAX                    0x8FFFFFFF
+#define BR_CODE_END_OF_BRA             0xFF0000FF
+#define LEGACY_BR_CODE_END_OF_BRA      0xFFFFFFFF
+
+struct bootrec {
+       __le32 code;
+       __le32 len;
+       u32 data[10];
+} __packed;
+
+/* Interface role definitions */
+#define BR_INTERFACE_ROLE_SERVER       0x0000
+#define BR_INTERFACE_ROLE_CLIENT       0x8000
+
+#define BR_DESC_PRIV_CAP_WEP           BIT(0)
+#define BR_DESC_PRIV_CAP_TKIP          BIT(1)
+#define BR_DESC_PRIV_CAP_MICHAEL       BIT(2)
+#define BR_DESC_PRIV_CAP_CCX_CP                BIT(3)
+#define BR_DESC_PRIV_CAP_CCX_MIC       BIT(4)
+#define BR_DESC_PRIV_CAP_AESCCMP       BIT(5)
+
+struct bootrec_desc {
+       __le16 modes;
+       __le16 flags;
+       __le32 rx_start;
+       __le32 rx_end;
+       u8 headroom;
+       u8 tailroom;
+       u8 tx_queues;
+       u8 tx_depth;
+       u8 privacy_caps;
+       u8 rx_keycache_size;
+       u8 time_size;
+       u8 padding;
+       u8 rates[16];
+       u8 padding2[4];
+       __le16 rx_mtu;
+} __packed;
+
+#define FW_FMAC 0x464d4143
+#define FW_LM86 0x4c4d3836
+#define FW_LM87 0x4c4d3837
+#define FW_LM20 0x4c4d3230
+
+struct bootrec_comp_id {
+       __le32 fw_variant;
+} __packed;
+
+struct bootrec_comp_ver {
+       char fw_version[24];
+} __packed;
+
+struct bootrec_end {
+       __le16 crc;
+       u8 padding[2];
+       u8 md5[16];
+} __packed;
 
 /* provide 16 bytes for the transport back-end */
 #define P54_TX_INFO_DATA_SIZE          16
@@ -55,34 +91,30 @@ enum p54_control_frame_types {
 struct p54_tx_info {
        u32 start_addr;
        u32 end_addr;
-       void *data[P54_TX_INFO_DATA_SIZE / sizeof(void *)];
+       union {
+               void *data[P54_TX_INFO_DATA_SIZE / sizeof(void *)];
+               struct {
+                       u32 extra_len;
+               };
+       };
 };
 
 #define P54_MAX_CTRL_FRAME_LEN         0x1000
 
-#define P54_HDR_FLAG_CONTROL           BIT(15)
-#define P54_HDR_FLAG_CONTROL_OPSET     (BIT(15) + BIT(0))
-
-struct p54_hdr {
-       __le16 flags;
-       __le16 len;
-       __le32 req_id;
-       __le16 type;    /* enum p54_control_frame_types */
-       u8 rts_tries;
-       u8 tries;
-       u8 data[0];
-} __attribute__ ((packed));
-
-#define FREE_AFTER_TX(skb)                                             \
-       ((((struct p54_hdr *) ((struct sk_buff *) skb)->data)->         \
-       flags) == cpu_to_le16(P54_HDR_FLAG_CONTROL_OPSET))
+#define P54_SET_QUEUE(queue, ai_fs, cw_min, cw_max, _txop)     \
+do {                                                           \
+       queue.aifs = cpu_to_le16(ai_fs);                        \
+       queue.cwmin = cpu_to_le16(cw_min);                      \
+       queue.cwmax = cpu_to_le16(cw_max);                      \
+       queue.txop = cpu_to_le16(_txop);                        \
+} while (0)
 
 struct p54_edcf_queue_param {
        __le16 aifs;
        __le16 cwmin;
        __le16 cwmax;
        __le16 txop;
-} __attribute__ ((packed));
+} __packed;
 
 struct p54_rssi_linear_approximation {
        s16 mul;
@@ -101,13 +133,6 @@ struct p54_cal_database {
 
 #define EEPROM_READBACK_LEN 0x3fc
 
-#define ISL38XX_DEV_FIRMWARE_ADDR 0x20000
-
-#define FW_FMAC 0x464d4143
-#define FW_LM86 0x4c4d3836
-#define FW_LM87 0x4c4d3837
-#define FW_LM20 0x4c4d3230
-
 enum fw_state {
        FW_STATE_OFF,
        FW_STATE_BOOTING,
@@ -138,6 +163,7 @@ struct p54_common {
        void (*tx)(struct ieee80211_hw *dev, struct sk_buff *skb);
        int (*open)(struct ieee80211_hw *dev);
        void (*stop)(struct ieee80211_hw *dev);
+       struct sk_buff_head tx_pending;
        struct sk_buff_head tx_queue;
        struct mutex conf_mutex;
 
@@ -156,6 +182,7 @@ struct p54_common {
 
        /* (e)DCF / QOS state */
        bool use_short_slot;
+       spinlock_t tx_stats_lock;
        struct ieee80211_tx_queue_stats tx_stats[8];
        struct p54_edcf_queue_param qos_params[8];
 
@@ -181,7 +208,7 @@ struct p54_common {
        u32 tsf_low32, tsf_high32;
        u32 basic_rate_mask;
        u16 aid;
-       struct sk_buff *cached_beacon;
+       __le32 beacon_req_id;
 
        /* cryptographic engine information */
        u8 privacy_caps;
@@ -202,15 +229,20 @@ struct p54_common {
        /* eeprom handling */
        void *eeprom;
        struct completion eeprom_comp;
+       struct mutex eeprom_mutex;
 };
 
+/* interfaces for the drivers */
 int p54_rx(struct ieee80211_hw *dev, struct sk_buff *skb);
 void p54_free_skb(struct ieee80211_hw *dev, struct sk_buff *skb);
 int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw);
 int p54_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);
 
+void p54_unregister_common(struct ieee80211_hw *dev);
+
 #endif /* P54_H */
diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c
deleted file mode 100644 (file)
index 22ca122..0000000
+++ /dev/null
@@ -1,2688 +0,0 @@
-/*
- * Common code for mac80211 Prism54 drivers
- *
- * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
- * Copyright (c) 2007, Christian Lamparter <chunkeey@web.de>
- * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
- *
- * Based on:
- * - the islsm (softmac prism54) driver, which is:
- *   Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
- * - stlc45xx driver
- *   Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/init.h>
-#include <linux/firmware.h>
-#include <linux/etherdevice.h>
-
-#include <net/mac80211.h>
-#ifdef CONFIG_P54_LEDS
-#include <linux/leds.h>
-#endif /* CONFIG_P54_LEDS */
-
-#include "p54.h"
-#include "p54common.h"
-
-static int modparam_nohwcrypt;
-module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO);
-MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");
-MODULE_AUTHOR("Michael Wu <flamingice@sourmilk.net>");
-MODULE_DESCRIPTION("Softmac Prism54 common code");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("prism54common");
-
-static struct ieee80211_rate p54_bgrates[] = {
-       { .bitrate = 10, .hw_value = 0, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
-       { .bitrate = 20, .hw_value = 1, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
-       { .bitrate = 55, .hw_value = 2, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
-       { .bitrate = 110, .hw_value = 3, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
-       { .bitrate = 60, .hw_value = 4, },
-       { .bitrate = 90, .hw_value = 5, },
-       { .bitrate = 120, .hw_value = 6, },
-       { .bitrate = 180, .hw_value = 7, },
-       { .bitrate = 240, .hw_value = 8, },
-       { .bitrate = 360, .hw_value = 9, },
-       { .bitrate = 480, .hw_value = 10, },
-       { .bitrate = 540, .hw_value = 11, },
-};
-
-static struct ieee80211_channel p54_bgchannels[] = {
-       { .center_freq = 2412, .hw_value = 1, },
-       { .center_freq = 2417, .hw_value = 2, },
-       { .center_freq = 2422, .hw_value = 3, },
-       { .center_freq = 2427, .hw_value = 4, },
-       { .center_freq = 2432, .hw_value = 5, },
-       { .center_freq = 2437, .hw_value = 6, },
-       { .center_freq = 2442, .hw_value = 7, },
-       { .center_freq = 2447, .hw_value = 8, },
-       { .center_freq = 2452, .hw_value = 9, },
-       { .center_freq = 2457, .hw_value = 10, },
-       { .center_freq = 2462, .hw_value = 11, },
-       { .center_freq = 2467, .hw_value = 12, },
-       { .center_freq = 2472, .hw_value = 13, },
-       { .center_freq = 2484, .hw_value = 14, },
-};
-
-static struct ieee80211_supported_band band_2GHz = {
-       .channels = p54_bgchannels,
-       .n_channels = ARRAY_SIZE(p54_bgchannels),
-       .bitrates = p54_bgrates,
-       .n_bitrates = ARRAY_SIZE(p54_bgrates),
-};
-
-static struct ieee80211_rate p54_arates[] = {
-       { .bitrate = 60, .hw_value = 4, },
-       { .bitrate = 90, .hw_value = 5, },
-       { .bitrate = 120, .hw_value = 6, },
-       { .bitrate = 180, .hw_value = 7, },
-       { .bitrate = 240, .hw_value = 8, },
-       { .bitrate = 360, .hw_value = 9, },
-       { .bitrate = 480, .hw_value = 10, },
-       { .bitrate = 540, .hw_value = 11, },
-};
-
-static struct ieee80211_channel p54_achannels[] = {
-       { .center_freq = 4920 },
-       { .center_freq = 4940 },
-       { .center_freq = 4960 },
-       { .center_freq = 4980 },
-       { .center_freq = 5040 },
-       { .center_freq = 5060 },
-       { .center_freq = 5080 },
-       { .center_freq = 5170 },
-       { .center_freq = 5180 },
-       { .center_freq = 5190 },
-       { .center_freq = 5200 },
-       { .center_freq = 5210 },
-       { .center_freq = 5220 },
-       { .center_freq = 5230 },
-       { .center_freq = 5240 },
-       { .center_freq = 5260 },
-       { .center_freq = 5280 },
-       { .center_freq = 5300 },
-       { .center_freq = 5320 },
-       { .center_freq = 5500 },
-       { .center_freq = 5520 },
-       { .center_freq = 5540 },
-       { .center_freq = 5560 },
-       { .center_freq = 5580 },
-       { .center_freq = 5600 },
-       { .center_freq = 5620 },
-       { .center_freq = 5640 },
-       { .center_freq = 5660 },
-       { .center_freq = 5680 },
-       { .center_freq = 5700 },
-       { .center_freq = 5745 },
-       { .center_freq = 5765 },
-       { .center_freq = 5785 },
-       { .center_freq = 5805 },
-       { .center_freq = 5825 },
-};
-
-static struct ieee80211_supported_band band_5GHz = {
-       .channels = p54_achannels,
-       .n_channels = ARRAY_SIZE(p54_achannels),
-       .bitrates = p54_arates,
-       .n_bitrates = ARRAY_SIZE(p54_arates),
-};
-
-int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw)
-{
-       struct p54_common *priv = dev->priv;
-       struct bootrec_exp_if *exp_if;
-       struct bootrec *bootrec;
-       u32 *data = (u32 *)fw->data;
-       u32 *end_data = (u32 *)fw->data + (fw->size >> 2);
-       u8 *fw_version = NULL;
-       size_t len;
-       int i;
-       int maxlen;
-
-       if (priv->rx_start)
-               return 0;
-
-       while (data < end_data && *data)
-               data++;
-
-       while (data < end_data && !*data)
-               data++;
-
-       bootrec = (struct bootrec *) data;
-
-       while (bootrec->data <= end_data &&
-              (bootrec->data + (len = le32_to_cpu(bootrec->len))) <= end_data) {
-               u32 code = le32_to_cpu(bootrec->code);
-               switch (code) {
-               case BR_CODE_COMPONENT_ID:
-                       priv->fw_interface = be32_to_cpup((__be32 *)
-                                            bootrec->data);
-                       switch (priv->fw_interface) {
-                       case FW_LM86:
-                       case FW_LM20:
-                       case FW_LM87: {
-                               char *iftype = (char *)bootrec->data;
-                               printk(KERN_INFO "%s: p54 detected a LM%c%c "
-                                                "firmware\n",
-                                       wiphy_name(dev->wiphy),
-                                       iftype[2], iftype[3]);
-                               break;
-                               }
-                       case FW_FMAC:
-                       default:
-                               printk(KERN_ERR "%s: unsupported firmware\n",
-                                       wiphy_name(dev->wiphy));
-                               return -ENODEV;
-                       }
-                       break;
-               case BR_CODE_COMPONENT_VERSION:
-                       /* 24 bytes should be enough for all firmwares */
-                       if (strnlen((unsigned char*)bootrec->data, 24) < 24)
-                               fw_version = (unsigned char*)bootrec->data;
-                       break;
-               case BR_CODE_DESCR: {
-                       struct bootrec_desc *desc =
-                               (struct bootrec_desc *)bootrec->data;
-                       priv->rx_start = le32_to_cpu(desc->rx_start);
-                       /* FIXME add sanity checking */
-                       priv->rx_end = le32_to_cpu(desc->rx_end) - 0x3500;
-                       priv->headroom = desc->headroom;
-                       priv->tailroom = desc->tailroom;
-                       priv->privacy_caps = desc->privacy_caps;
-                       priv->rx_keycache_size = desc->rx_keycache_size;
-                       if (le32_to_cpu(bootrec->len) == 11)
-                               priv->rx_mtu = le16_to_cpu(desc->rx_mtu);
-                       else
-                               priv->rx_mtu = (size_t)
-                                       0x620 - priv->tx_hdr_len;
-                       maxlen = priv->tx_hdr_len + /* USB devices */
-                                sizeof(struct p54_rx_data) +
-                                4 + /* rx alignment */
-                                IEEE80211_MAX_FRAG_THRESHOLD;
-                       if (priv->rx_mtu > maxlen && PAGE_SIZE == 4096) {
-                               printk(KERN_INFO "p54: rx_mtu reduced from %d "
-                                                "to %d\n", priv->rx_mtu,
-                                                maxlen);
-                               priv->rx_mtu = maxlen;
-                       }
-                       break;
-                       }
-               case BR_CODE_EXPOSED_IF:
-                       exp_if = (struct bootrec_exp_if *) bootrec->data;
-                       for (i = 0; i < (len * sizeof(*exp_if) / 4); i++)
-                               if (exp_if[i].if_id == cpu_to_le16(0x1a))
-                                       priv->fw_var = le16_to_cpu(exp_if[i].variant);
-                       break;
-               case BR_CODE_DEPENDENT_IF:
-                       break;
-               case BR_CODE_END_OF_BRA:
-               case LEGACY_BR_CODE_END_OF_BRA:
-                       end_data = NULL;
-                       break;
-               default:
-                       break;
-               }
-               bootrec = (struct bootrec *)&bootrec->data[len];
-       }
-
-       if (fw_version)
-               printk(KERN_INFO "%s: FW rev %s - Softmac protocol %x.%x\n",
-                       wiphy_name(dev->wiphy), fw_version,
-                       priv->fw_var >> 8, priv->fw_var & 0xff);
-
-       if (priv->fw_var < 0x500)
-               printk(KERN_INFO "%s: you are using an obsolete firmware. "
-                      "visit http://wireless.kernel.org/en/users/Drivers/p54 "
-                      "and grab one for \"kernel >= 2.6.28\"!\n",
-                       wiphy_name(dev->wiphy));
-
-       if (priv->fw_var >= 0x300) {
-               /* Firmware supports QoS, use it! */
-               priv->tx_stats[P54_QUEUE_AC_VO].limit = 3;
-               priv->tx_stats[P54_QUEUE_AC_VI].limit = 4;
-               priv->tx_stats[P54_QUEUE_AC_BE].limit = 3;
-               priv->tx_stats[P54_QUEUE_AC_BK].limit = 2;
-               dev->queues = P54_QUEUE_AC_NUM;
-       }
-
-       if (!modparam_nohwcrypt) {
-               printk(KERN_INFO "%s: cryptographic accelerator "
-                                "WEP:%s, TKIP:%s, CCMP:%s\n",
-                       wiphy_name(dev->wiphy),
-                       (priv->privacy_caps & BR_DESC_PRIV_CAP_WEP) ? "YES" :
-                       "no", (priv->privacy_caps & (BR_DESC_PRIV_CAP_TKIP |
-                        BR_DESC_PRIV_CAP_MICHAEL)) ? "YES" : "no",
-                       (priv->privacy_caps & BR_DESC_PRIV_CAP_AESCCMP) ?
-                       "YES" : "no");
-
-               if (priv->rx_keycache_size) {
-                       /*
-                        * NOTE:
-                        *
-                        * The firmware provides at most 255 (0 - 254) slots
-                        * for keys which are then used to offload decryption.
-                        * As a result the 255 entry (aka 0xff) can be used
-                        * safely by the driver to mark keys that didn't fit
-                        * into the full cache. This trick saves us from
-                        * keeping a extra list for uploaded keys.
-                        */
-
-                       priv->used_rxkeys = kzalloc(BITS_TO_LONGS(
-                               priv->rx_keycache_size), GFP_KERNEL);
-
-                       if (!priv->used_rxkeys)
-                               return -ENOMEM;
-               }
-       }
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(p54_parse_firmware);
-
-static int p54_convert_rev0(struct ieee80211_hw *dev,
-                           struct pda_pa_curve_data *curve_data)
-{
-       struct p54_common *priv = dev->priv;
-       struct p54_pa_curve_data_sample *dst;
-       struct pda_pa_curve_data_sample_rev0 *src;
-       size_t cd_len = sizeof(*curve_data) +
-               (curve_data->points_per_channel*sizeof(*dst) + 2) *
-                curve_data->channels;
-       unsigned int i, j;
-       void *source, *target;
-
-       priv->curve_data = kmalloc(sizeof(*priv->curve_data) + cd_len,
-                                  GFP_KERNEL);
-       if (!priv->curve_data)
-               return -ENOMEM;
-
-       priv->curve_data->entries = curve_data->channels;
-       priv->curve_data->entry_size = sizeof(__le16) +
-               sizeof(*dst) * curve_data->points_per_channel;
-       priv->curve_data->offset = offsetof(struct pda_pa_curve_data, data);
-       priv->curve_data->len = cd_len;
-       memcpy(priv->curve_data->data, curve_data, sizeof(*curve_data));
-       source = curve_data->data;
-       target = ((struct pda_pa_curve_data *) priv->curve_data->data)->data;
-       for (i = 0; i < curve_data->channels; i++) {
-               __le16 *freq = source;
-               source += sizeof(__le16);
-               *((__le16 *)target) = *freq;
-               target += sizeof(__le16);
-               for (j = 0; j < curve_data->points_per_channel; j++) {
-                       dst = target;
-                       src = source;
-
-                       dst->rf_power = src->rf_power;
-                       dst->pa_detector = src->pa_detector;
-                       dst->data_64qam = src->pcv;
-                       /* "invent" the points for the other modulations */
-#define SUB(x,y) (u8)((x) - (y)) > (x) ? 0 : (x) - (y)
-                       dst->data_16qam = SUB(src->pcv, 12);
-                       dst->data_qpsk = SUB(dst->data_16qam, 12);
-                       dst->data_bpsk = SUB(dst->data_qpsk, 12);
-                       dst->data_barker = SUB(dst->data_bpsk, 14);
-#undef SUB
-                       target += sizeof(*dst);
-                       source += sizeof(*src);
-               }
-       }
-
-       return 0;
-}
-
-static int p54_convert_rev1(struct ieee80211_hw *dev,
-                           struct pda_pa_curve_data *curve_data)
-{
-       struct p54_common *priv = dev->priv;
-       struct p54_pa_curve_data_sample *dst;
-       struct pda_pa_curve_data_sample_rev1 *src;
-       size_t cd_len = sizeof(*curve_data) +
-               (curve_data->points_per_channel*sizeof(*dst) + 2) *
-                curve_data->channels;
-       unsigned int i, j;
-       void *source, *target;
-
-       priv->curve_data = kzalloc(cd_len + sizeof(*priv->curve_data),
-                                  GFP_KERNEL);
-       if (!priv->curve_data)
-               return -ENOMEM;
-
-       priv->curve_data->entries = curve_data->channels;
-       priv->curve_data->entry_size = sizeof(__le16) +
-               sizeof(*dst) * curve_data->points_per_channel;
-       priv->curve_data->offset = offsetof(struct pda_pa_curve_data, data);
-       priv->curve_data->len = cd_len;
-       memcpy(priv->curve_data->data, curve_data, sizeof(*curve_data));
-       source = curve_data->data;
-       target = ((struct pda_pa_curve_data *) priv->curve_data->data)->data;
-       for (i = 0; i < curve_data->channels; i++) {
-               __le16 *freq = source;
-               source += sizeof(__le16);
-               *((__le16 *)target) = *freq;
-               target += sizeof(__le16);
-               for (j = 0; j < curve_data->points_per_channel; j++) {
-                       memcpy(target, source, sizeof(*src));
-
-                       target += sizeof(*dst);
-                       source += sizeof(*src);
-               }
-               source++;
-       }
-
-       return 0;
-}
-
-static const char *p54_rf_chips[] = { "NULL", "Duette3", "Duette2",
-                              "Frisbee", "Xbow", "Longbow", "NULL", "NULL" };
-static int p54_init_xbow_synth(struct ieee80211_hw *dev);
-
-static void p54_parse_rssical(struct ieee80211_hw *dev, void *data, int len,
-                            u16 type)
-{
-       struct p54_common *priv = dev->priv;
-       int offset = (type == PDR_RSSI_LINEAR_APPROXIMATION_EXTENDED) ? 2 : 0;
-       int entry_size = sizeof(struct pda_rssi_cal_entry) + offset;
-       int num_entries = (type == PDR_RSSI_LINEAR_APPROXIMATION) ? 1 : 2;
-       int i;
-
-       if (len != (entry_size * num_entries)) {
-               printk(KERN_ERR "%s: unknown rssi calibration data packing "
-                                " type:(%x) len:%d.\n",
-                      wiphy_name(dev->wiphy), type, len);
-
-               print_hex_dump_bytes("rssical:", DUMP_PREFIX_NONE,
-                                    data, len);
-
-               printk(KERN_ERR "%s: please report this issue.\n",
-                       wiphy_name(dev->wiphy));
-               return;
-       }
-
-       for (i = 0; i < num_entries; i++) {
-               struct pda_rssi_cal_entry *cal = data +
-                                                (offset + i * entry_size);
-               priv->rssical_db[i].mul = (s16) le16_to_cpu(cal->mul);
-               priv->rssical_db[i].add = (s16) le16_to_cpu(cal->add);
-       }
-}
-
-static void p54_parse_default_country(struct ieee80211_hw *dev,
-                                     void *data, int len)
-{
-       struct pda_country *country;
-
-       if (len != sizeof(*country)) {
-               printk(KERN_ERR "%s: found possible invalid default country "
-                               "eeprom entry. (entry size: %d)\n",
-                      wiphy_name(dev->wiphy), len);
-
-               print_hex_dump_bytes("country:", DUMP_PREFIX_NONE,
-                                    data, len);
-
-               printk(KERN_ERR "%s: please report this issue.\n",
-                       wiphy_name(dev->wiphy));
-               return;
-       }
-
-       country = (struct pda_country *) data;
-       if (country->flags == PDR_COUNTRY_CERT_CODE_PSEUDO)
-               regulatory_hint(dev->wiphy, country->alpha2);
-       else {
-               /* TODO:
-                * write a shared/common function that converts
-                * "Regulatory domain codes" (802.11-2007 14.8.2.2)
-                * into ISO/IEC 3166-1 alpha2 for regulatory_hint.
-                */
-       }
-}
-
-static int p54_convert_output_limits(struct ieee80211_hw *dev,
-                                    u8 *data, size_t len)
-{
-       struct p54_common *priv = dev->priv;
-
-       if (len < 2)
-               return -EINVAL;
-
-       if (data[0] != 0) {
-               printk(KERN_ERR "%s: unknown output power db revision:%x\n",
-                      wiphy_name(dev->wiphy), data[0]);
-               return -EINVAL;
-       }
-
-       if (2 + data[1] * sizeof(struct pda_channel_output_limit) > len)
-               return -EINVAL;
-
-       priv->output_limit = kmalloc(data[1] *
-               sizeof(struct pda_channel_output_limit) +
-               sizeof(*priv->output_limit), GFP_KERNEL);
-
-       if (!priv->output_limit)
-               return -ENOMEM;
-
-       priv->output_limit->offset = 0;
-       priv->output_limit->entries = data[1];
-       priv->output_limit->entry_size =
-               sizeof(struct pda_channel_output_limit);
-       priv->output_limit->len = priv->output_limit->entry_size *
-                                 priv->output_limit->entries +
-                                 priv->output_limit->offset;
-
-       memcpy(priv->output_limit->data, &data[2],
-              data[1] * sizeof(struct pda_channel_output_limit));
-
-       return 0;
-}
-
-static struct p54_cal_database *p54_convert_db(struct pda_custom_wrapper *src,
-                                              size_t total_len)
-{
-       struct p54_cal_database *dst;
-       size_t payload_len, entries, entry_size, offset;
-
-       payload_len = le16_to_cpu(src->len);
-       entries = le16_to_cpu(src->entries);
-       entry_size = le16_to_cpu(src->entry_size);
-       offset = le16_to_cpu(src->offset);
-       if (((entries * entry_size + offset) != payload_len) ||
-            (payload_len + sizeof(*src) != total_len))
-               return NULL;
-
-       dst = kmalloc(sizeof(*dst) + payload_len, GFP_KERNEL);
-       if (!dst)
-               return NULL;
-
-       dst->entries = entries;
-       dst->entry_size = entry_size;
-       dst->offset = offset;
-       dst->len = payload_len;
-
-       memcpy(dst->data, src->data, payload_len);
-       return dst;
-}
-
-int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len)
-{
-       struct p54_common *priv = dev->priv;
-       struct eeprom_pda_wrap *wrap = NULL;
-       struct pda_entry *entry;
-       unsigned int data_len, entry_len;
-       void *tmp;
-       int err;
-       u8 *end = (u8 *)eeprom + len;
-       u16 synth = 0;
-
-       wrap = (struct eeprom_pda_wrap *) eeprom;
-       entry = (void *)wrap->data + le16_to_cpu(wrap->len);
-
-       /* verify that at least the entry length/code fits */
-       while ((u8 *)entry <= end - sizeof(*entry)) {
-               entry_len = le16_to_cpu(entry->len);
-               data_len = ((entry_len - 1) << 1);
-
-               /* abort if entry exceeds whole structure */
-               if ((u8 *)entry + sizeof(*entry) + data_len > end)
-                       break;
-
-               switch (le16_to_cpu(entry->code)) {
-               case PDR_MAC_ADDRESS:
-                       if (data_len != ETH_ALEN)
-                               break;
-                       SET_IEEE80211_PERM_ADDR(dev, entry->data);
-                       break;
-               case PDR_PRISM_PA_CAL_OUTPUT_POWER_LIMITS:
-                       if (priv->output_limit)
-                               break;
-                       err = p54_convert_output_limits(dev, entry->data,
-                                                       data_len);
-                       if (err)
-                               goto err;
-                       break;
-               case PDR_PRISM_PA_CAL_CURVE_DATA: {
-                       struct pda_pa_curve_data *curve_data =
-                               (struct pda_pa_curve_data *)entry->data;
-                       if (data_len < sizeof(*curve_data)) {
-                               err = -EINVAL;
-                               goto err;
-                       }
-
-                       switch (curve_data->cal_method_rev) {
-                       case 0:
-                               err = p54_convert_rev0(dev, curve_data);
-                               break;
-                       case 1:
-                               err = p54_convert_rev1(dev, curve_data);
-                               break;
-                       default:
-                               printk(KERN_ERR "%s: unknown curve data "
-                                               "revision %d\n",
-                                               wiphy_name(dev->wiphy),
-                                               curve_data->cal_method_rev);
-                               err = -ENODEV;
-                               break;
-                       }
-                       if (err)
-                               goto err;
-                       }
-                       break;
-               case PDR_PRISM_ZIF_TX_IQ_CALIBRATION:
-                       priv->iq_autocal = kmalloc(data_len, GFP_KERNEL);
-                       if (!priv->iq_autocal) {
-                               err = -ENOMEM;
-                               goto err;
-                       }
-
-                       memcpy(priv->iq_autocal, entry->data, data_len);
-                       priv->iq_autocal_len = data_len / sizeof(struct pda_iq_autocal_entry);
-                       break;
-               case PDR_DEFAULT_COUNTRY:
-                       p54_parse_default_country(dev, entry->data, data_len);
-                       break;
-               case PDR_INTERFACE_LIST:
-                       tmp = entry->data;
-                       while ((u8 *)tmp < entry->data + data_len) {
-                               struct bootrec_exp_if *exp_if = tmp;
-                               if (le16_to_cpu(exp_if->if_id) == 0xf)
-                                       synth = le16_to_cpu(exp_if->variant);
-                               tmp += sizeof(struct bootrec_exp_if);
-                       }
-                       break;
-               case PDR_HARDWARE_PLATFORM_COMPONENT_ID:
-                       if (data_len < 2)
-                               break;
-                       priv->version = *(u8 *)(entry->data + 1);
-                       break;
-               case PDR_RSSI_LINEAR_APPROXIMATION:
-               case PDR_RSSI_LINEAR_APPROXIMATION_DUAL_BAND:
-               case PDR_RSSI_LINEAR_APPROXIMATION_EXTENDED:
-                       p54_parse_rssical(dev, entry->data, data_len,
-                                         le16_to_cpu(entry->code));
-                       break;
-               case PDR_RSSI_LINEAR_APPROXIMATION_CUSTOM: {
-                       __le16 *src = (void *) entry->data;
-                       s16 *dst = (void *) &priv->rssical_db;
-                       int i;
-
-                       if (data_len != sizeof(priv->rssical_db)) {
-                               err = -EINVAL;
-                               goto err;
-                       }
-                       for (i = 0; i < sizeof(priv->rssical_db) /
-                                       sizeof(*src); i++)
-                               *(dst++) = (s16) le16_to_cpu(*(src++));
-                       }
-                       break;
-               case PDR_PRISM_PA_CAL_OUTPUT_POWER_LIMITS_CUSTOM: {
-                       struct pda_custom_wrapper *pda = (void *) entry->data;
-                       if (priv->output_limit || data_len < sizeof(*pda))
-                               break;
-                       priv->output_limit = p54_convert_db(pda, data_len);
-                       }
-                       break;
-               case PDR_PRISM_PA_CAL_CURVE_DATA_CUSTOM: {
-                       struct pda_custom_wrapper *pda = (void *) entry->data;
-                       if (priv->curve_data || data_len < sizeof(*pda))
-                               break;
-                       priv->curve_data = p54_convert_db(pda, data_len);
-                       }
-                       break;
-               case PDR_END:
-                       /* make it overrun */
-                       entry_len = len;
-                       break;
-               case PDR_MANUFACTURING_PART_NUMBER:
-               case PDR_PDA_VERSION:
-               case PDR_NIC_SERIAL_NUMBER:
-               case PDR_REGULATORY_DOMAIN_LIST:
-               case PDR_TEMPERATURE_TYPE:
-               case PDR_PRISM_PCI_IDENTIFIER:
-               case PDR_COUNTRY_INFORMATION:
-               case PDR_OEM_NAME:
-               case PDR_PRODUCT_NAME:
-               case PDR_UTF8_OEM_NAME:
-               case PDR_UTF8_PRODUCT_NAME:
-               case PDR_COUNTRY_LIST:
-               case PDR_ANTENNA_GAIN:
-               case PDR_PRISM_INDIGO_PA_CALIBRATION_DATA:
-               case PDR_REGULATORY_POWER_LIMITS:
-               case PDR_RADIATED_TRANSMISSION_CORRECTION:
-               case PDR_PRISM_TX_IQ_CALIBRATION:
-               case PDR_BASEBAND_REGISTERS:
-               case PDR_PER_CHANNEL_BASEBAND_REGISTERS:
-                       break;
-               default:
-                       printk(KERN_INFO "%s: unknown eeprom code : 0x%x\n",
-                               wiphy_name(dev->wiphy),
-                               le16_to_cpu(entry->code));
-                       break;
-               }
-
-               entry = (void *)entry + (entry_len + 1)*2;
-       }
-
-       if (!synth || !priv->iq_autocal || !priv->output_limit ||
-           !priv->curve_data) {
-               printk(KERN_ERR "%s: not all required entries found in eeprom!\n",
-                       wiphy_name(dev->wiphy));
-               err = -EINVAL;
-               goto err;
-       }
-
-       priv->rxhw = synth & PDR_SYNTH_FRONTEND_MASK;
-       if (priv->rxhw == PDR_SYNTH_FRONTEND_XBOW)
-               p54_init_xbow_synth(dev);
-       if (!(synth & PDR_SYNTH_24_GHZ_DISABLED))
-               dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &band_2GHz;
-       if (!(synth & PDR_SYNTH_5_GHZ_DISABLED))
-               dev->wiphy->bands[IEEE80211_BAND_5GHZ] = &band_5GHz;
-       if ((synth & PDR_SYNTH_RX_DIV_MASK) == PDR_SYNTH_RX_DIV_SUPPORTED)
-               priv->rx_diversity_mask = 3;
-       if ((synth & PDR_SYNTH_TX_DIV_MASK) == PDR_SYNTH_TX_DIV_SUPPORTED)
-               priv->tx_diversity_mask = 3;
-
-       if (!is_valid_ether_addr(dev->wiphy->perm_addr)) {
-               u8 perm_addr[ETH_ALEN];
-
-               printk(KERN_WARNING "%s: Invalid hwaddr! Using randomly generated MAC addr\n",
-                       wiphy_name(dev->wiphy));
-               random_ether_addr(perm_addr);
-               SET_IEEE80211_PERM_ADDR(dev, perm_addr);
-       }
-
-       printk(KERN_INFO "%s: hwaddr %pM, MAC:isl38%02x RF:%s\n",
-               wiphy_name(dev->wiphy),
-               dev->wiphy->perm_addr,
-               priv->version, p54_rf_chips[priv->rxhw]);
-
-       return 0;
-
-  err:
-       if (priv->iq_autocal) {
-               kfree(priv->iq_autocal);
-               priv->iq_autocal = NULL;
-       }
-
-       if (priv->output_limit) {
-               kfree(priv->output_limit);
-               priv->output_limit = NULL;
-       }
-
-       if (priv->curve_data) {
-               kfree(priv->curve_data);
-               priv->curve_data = NULL;
-       }
-
-       printk(KERN_ERR "%s: eeprom parse failed!\n",
-               wiphy_name(dev->wiphy));
-       return err;
-}
-EXPORT_SYMBOL_GPL(p54_parse_eeprom);
-
-static int p54_rssi_to_dbm(struct ieee80211_hw *dev, int rssi)
-{
-       struct p54_common *priv = dev->priv;
-       int band = dev->conf.channel->band;
-
-       if (priv->rxhw != PDR_SYNTH_FRONTEND_LONGBOW)
-               return ((rssi * priv->rssical_db[band].mul) / 64 +
-                        priv->rssical_db[band].add) / 4;
-       else
-               /*
-                * TODO: find the correct formula
-                */
-               return ((rssi * priv->rssical_db[band].mul) / 64 +
-                        priv->rssical_db[band].add) / 4;
-}
-
-static int p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb)
-{
-       struct p54_common *priv = dev->priv;
-       struct p54_rx_data *hdr = (struct p54_rx_data *) skb->data;
-       struct ieee80211_rx_status rx_status = {0};
-       u16 freq = le16_to_cpu(hdr->freq);
-       size_t header_len = sizeof(*hdr);
-       u32 tsf32;
-       u8 rate = hdr->rate & 0xf;
-
-       /*
-        * If the device is in a unspecified state we have to
-        * ignore all data frames. Else we could end up with a
-        * nasty crash.
-        */
-       if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED))
-               return 0;
-
-       if (!(hdr->flags & cpu_to_le16(P54_HDR_FLAG_DATA_IN_FCS_GOOD))) {
-               return 0;
-       }
-
-       if (hdr->decrypt_status == P54_DECRYPT_OK)
-               rx_status.flag |= RX_FLAG_DECRYPTED;
-       if ((hdr->decrypt_status == P54_DECRYPT_FAIL_MICHAEL) ||
-           (hdr->decrypt_status == P54_DECRYPT_FAIL_TKIP))
-               rx_status.flag |= RX_FLAG_MMIC_ERROR;
-
-       rx_status.signal = p54_rssi_to_dbm(dev, hdr->rssi);
-       rx_status.noise = priv->noise;
-       if (hdr->rate & 0x10)
-               rx_status.flag |= RX_FLAG_SHORTPRE;
-       if (dev->conf.channel->band == IEEE80211_BAND_5GHZ)
-               rx_status.rate_idx = (rate < 4) ? 0 : rate - 4;
-       else
-               rx_status.rate_idx = rate;
-
-       rx_status.freq = freq;
-       rx_status.band =  dev->conf.channel->band;
-       rx_status.antenna = hdr->antenna;
-
-       tsf32 = le32_to_cpu(hdr->tsf32);
-       if (tsf32 < priv->tsf_low32)
-               priv->tsf_high32++;
-       rx_status.mactime = ((u64)priv->tsf_high32) << 32 | tsf32;
-       priv->tsf_low32 = tsf32;
-
-       rx_status.flag |= RX_FLAG_TSFT;
-
-       if (hdr->flags & cpu_to_le16(P54_HDR_FLAG_DATA_ALIGN))
-               header_len += hdr->align[0];
-
-       skb_pull(skb, header_len);
-       skb_trim(skb, le16_to_cpu(hdr->len));
-
-       ieee80211_rx_irqsafe(dev, skb, &rx_status);
-
-       queue_delayed_work(dev->workqueue, &priv->work,
-                          msecs_to_jiffies(P54_STATISTICS_UPDATE));
-
-       return -1;
-}
-
-static void inline p54_wake_free_queues(struct ieee80211_hw *dev)
-{
-       struct p54_common *priv = dev->priv;
-       int i;
-
-       if (priv->mode == NL80211_IFTYPE_UNSPECIFIED)
-               return ;
-
-       for (i = 0; i < dev->queues; i++)
-               if (priv->tx_stats[i + P54_QUEUE_DATA].len <
-                   priv->tx_stats[i + P54_QUEUE_DATA].limit)
-                       ieee80211_wake_queue(dev, i);
-}
-
-void p54_free_skb(struct ieee80211_hw *dev, struct sk_buff *skb)
-{
-       struct p54_common *priv = dev->priv;
-       struct ieee80211_tx_info *info;
-       struct p54_tx_info *range;
-       unsigned long flags;
-
-       if (unlikely(!skb || !dev || !skb_queue_len(&priv->tx_queue)))
-               return;
-
-       /*
-        * don't try to free an already unlinked skb
-        */
-       if (unlikely((!skb->next) || (!skb->prev)))
-               return;
-
-       spin_lock_irqsave(&priv->tx_queue.lock, flags);
-       info = IEEE80211_SKB_CB(skb);
-       range = (void *)info->rate_driver_data;
-       if (skb->prev != (struct sk_buff *)&priv->tx_queue) {
-               struct ieee80211_tx_info *ni;
-               struct p54_tx_info *mr;
-
-               ni = IEEE80211_SKB_CB(skb->prev);
-               mr = (struct p54_tx_info *)ni->rate_driver_data;
-       }
-       if (skb->next != (struct sk_buff *)&priv->tx_queue) {
-               struct ieee80211_tx_info *ni;
-               struct p54_tx_info *mr;
-
-               ni = IEEE80211_SKB_CB(skb->next);
-               mr = (struct p54_tx_info *)ni->rate_driver_data;
-       }
-       __skb_unlink(skb, &priv->tx_queue);
-       spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
-       dev_kfree_skb_any(skb);
-       p54_wake_free_queues(dev);
-}
-EXPORT_SYMBOL_GPL(p54_free_skb);
-
-static struct sk_buff *p54_find_tx_entry(struct ieee80211_hw *dev,
-                                          __le32 req_id)
-{
-       struct p54_common *priv = dev->priv;
-       struct sk_buff *entry;
-       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;
-
-               if (hdr->req_id == req_id) {
-                       spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
-                       return entry;
-               }
-               entry = entry->next;
-       }
-       spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
-       return NULL;
-}
-
-static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb)
-{
-       struct p54_common *priv = dev->priv;
-       struct p54_hdr *hdr = (struct p54_hdr *) skb->data;
-       struct p54_frame_sent *payload = (struct p54_frame_sent *) hdr->data;
-       struct sk_buff *entry;
-       u32 addr = le32_to_cpu(hdr->req_id) - priv->headroom;
-       struct p54_tx_info *range = NULL;
-       unsigned long flags;
-       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;
-               struct p54_tx_data *entry_data;
-               unsigned int pad = 0, frame_len;
-
-               range = (void *)info->rate_driver_data;
-               if (range->start_addr != addr) {
-                       entry = entry->next;
-                       continue;
-               }
-
-               if (entry->next != (struct sk_buff *)&priv->tx_queue) {
-                       struct ieee80211_tx_info *ni;
-                       struct p54_tx_info *mr;
-
-                       ni = IEEE80211_SKB_CB(entry->next);
-                       mr = (struct p54_tx_info *)ni->rate_driver_data;
-               }
-
-               __skb_unlink(entry, &priv->tx_queue);
-
-               frame_len = entry->len;
-               entry_hdr = (struct p54_hdr *) entry->data;
-               entry_data = (struct p54_tx_data *) entry_hdr->data;
-               if (priv->tx_stats[entry_data->hw_queue].len)
-                       priv->tx_stats[entry_data->hw_queue].len--;
-               priv->stats.dot11ACKFailureCount += payload->tries - 1;
-               spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
-
-               /*
-                * Frames in P54_QUEUE_FWSCAN and P54_QUEUE_BEACON are
-                * generated by the driver. Therefore tx_status is bogus
-                * and we don't want to confuse the mac80211 stack.
-                */
-               if (unlikely(entry_data->hw_queue < P54_QUEUE_FWSCAN)) {
-                       if (entry_data->hw_queue == P54_QUEUE_BEACON)
-                               priv->cached_beacon = NULL;
-
-                       kfree_skb(entry);
-                       goto out;
-               }
-
-               /*
-                * Clear manually, ieee80211_tx_info_clear_status would
-                * clear the counts too and we need them.
-                */
-               memset(&info->status.ampdu_ack_len, 0,
-                      sizeof(struct ieee80211_tx_info) -
-                      offsetof(struct ieee80211_tx_info, status.ampdu_ack_len));
-               BUILD_BUG_ON(offsetof(struct ieee80211_tx_info,
-                                     status.ampdu_ack_len) != 23);
-
-               if (entry_hdr->flags & cpu_to_le16(P54_HDR_FLAG_DATA_ALIGN))
-                       pad = entry_data->align[0];
-
-               /* walk through the rates array and adjust the counts */
-               count = payload->tries;
-               for (idx = 0; idx < 4; idx++) {
-                       if (count >= info->status.rates[idx].count) {
-                               count -= info->status.rates[idx].count;
-                       } else if (count > 0) {
-                               info->status.rates[idx].count = count;
-                               count = 0;
-                       } else {
-                               info->status.rates[idx].idx = -1;
-                               info->status.rates[idx].count = 0;
-                       }
-               }
-
-               if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) &&
-                    (!payload->status))
-                       info->flags |= IEEE80211_TX_STAT_ACK;
-               if (payload->status & P54_TX_PSM_CANCELLED)
-                       info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
-               info->status.ack_signal = p54_rssi_to_dbm(dev,
-                               (int)payload->ack_rssi);
-
-               /* Undo all changes to the frame. */
-               switch (entry_data->key_type) {
-               case P54_CRYPTO_TKIPMICHAEL: {
-                       u8 *iv = (u8 *)(entry_data->align + pad +
-                                       entry_data->crypt_offset);
-
-                       /* Restore the original TKIP IV. */
-                       iv[2] = iv[0];
-                       iv[0] = iv[1];
-                       iv[1] = (iv[0] | 0x20) & 0x7f;  /* WEPSeed - 8.3.2.2 */
-
-                       frame_len -= 12; /* remove TKIP_MMIC + TKIP_ICV */
-                       break;
-                       }
-               case P54_CRYPTO_AESCCMP:
-                       frame_len -= 8; /* remove CCMP_MIC */
-                       break;
-               case P54_CRYPTO_WEP:
-                       frame_len -= 4; /* remove WEP_ICV */
-                       break;
-               }
-               skb_trim(entry, frame_len);
-               skb_pull(entry, sizeof(*hdr) + pad + sizeof(*entry_data));
-               ieee80211_tx_status_irqsafe(dev, entry);
-               goto out;
-       }
-       spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
-
-out:
-       p54_wake_free_queues(dev);
-}
-
-static void p54_rx_eeprom_readback(struct ieee80211_hw *dev,
-                                  struct sk_buff *skb)
-{
-       struct p54_hdr *hdr = (struct p54_hdr *) skb->data;
-       struct p54_eeprom_lm86 *eeprom = (struct p54_eeprom_lm86 *) hdr->data;
-       struct p54_common *priv = dev->priv;
-
-       if (!priv->eeprom)
-               return ;
-
-       if (priv->fw_var >= 0x509) {
-               memcpy(priv->eeprom, eeprom->v2.data,
-                      le16_to_cpu(eeprom->v2.len));
-       } else {
-               memcpy(priv->eeprom, eeprom->v1.data,
-                      le16_to_cpu(eeprom->v1.len));
-       }
-
-       complete(&priv->eeprom_comp);
-}
-
-static void p54_rx_stats(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_statistics *stats = (struct p54_statistics *) hdr->data;
-       u32 tsf32;
-
-       if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED))
-               return ;
-
-       tsf32 = le32_to_cpu(stats->tsf32);
-       if (tsf32 < priv->tsf_low32)
-               priv->tsf_high32++;
-       priv->tsf_low32 = tsf32;
-
-       priv->stats.dot11RTSFailureCount = le32_to_cpu(stats->rts_fail);
-       priv->stats.dot11RTSSuccessCount = le32_to_cpu(stats->rts_success);
-       priv->stats.dot11FCSErrorCount = le32_to_cpu(stats->rx_bad_fcs);
-
-       priv->noise = p54_rssi_to_dbm(dev, le32_to_cpu(stats->noise));
-
-       p54_free_skb(dev, p54_find_tx_entry(dev, hdr->req_id));
-}
-
-static void p54_rx_trap(struct ieee80211_hw *dev, struct sk_buff *skb)
-{
-       struct p54_common *priv = dev->priv;
-       struct p54_hdr *hdr = (struct p54_hdr *) skb->data;
-       struct p54_trap *trap = (struct p54_trap *) hdr->data;
-       u16 event = le16_to_cpu(trap->event);
-       u16 freq = le16_to_cpu(trap->frequency);
-
-       switch (event) {
-       case P54_TRAP_BEACON_TX:
-               break;
-       case P54_TRAP_RADAR:
-               printk(KERN_INFO "%s: radar (freq:%d MHz)\n",
-                       wiphy_name(dev->wiphy), freq);
-               break;
-       case P54_TRAP_NO_BEACON:
-               if (priv->vif)
-                       ieee80211_beacon_loss(priv->vif);
-               break;
-       case P54_TRAP_SCAN:
-               break;
-       case P54_TRAP_TBTT:
-               break;
-       case P54_TRAP_TIMER:
-               break;
-       default:
-               printk(KERN_INFO "%s: received event:%x freq:%d\n",
-                      wiphy_name(dev->wiphy), event, freq);
-               break;
-       }
-}
-
-static int p54_rx_control(struct ieee80211_hw *dev, struct sk_buff *skb)
-{
-       struct p54_hdr *hdr = (struct p54_hdr *) skb->data;
-
-       switch (le16_to_cpu(hdr->type)) {
-       case P54_CONTROL_TYPE_TXDONE:
-               p54_rx_frame_sent(dev, skb);
-               break;
-       case P54_CONTROL_TYPE_TRAP:
-               p54_rx_trap(dev, skb);
-               break;
-       case P54_CONTROL_TYPE_BBP:
-               break;
-       case P54_CONTROL_TYPE_STAT_READBACK:
-               p54_rx_stats(dev, skb);
-               break;
-       case P54_CONTROL_TYPE_EEPROM_READBACK:
-               p54_rx_eeprom_readback(dev, skb);
-               break;
-       default:
-               printk(KERN_DEBUG "%s: not handling 0x%02x type control frame\n",
-                      wiphy_name(dev->wiphy), le16_to_cpu(hdr->type));
-               break;
-       }
-
-       return 0;
-}
-
-/* returns zero if skb can be reused */
-int p54_rx(struct ieee80211_hw *dev, struct sk_buff *skb)
-{
-       u16 type = le16_to_cpu(*((__le16 *)skb->data));
-
-       if (type & P54_HDR_FLAG_CONTROL)
-               return p54_rx_control(dev, skb);
-       else
-               return p54_rx_data(dev, skb);
-}
-EXPORT_SYMBOL_GPL(p54_rx);
-
-/*
- * So, the firmware is somewhat stupid and doesn't know what places in its
- * memory incoming data should go to. By poking around in the firmware, we
- * can find some unused memory to upload our packets to. However, data that we
- * want the card to TX needs to stay intact until the card has told us that
- * it is done with it. This function finds empty places we can upload to and
- * marks allocated areas as reserved if necessary. p54_rx_frame_sent or
- * p54_free_skb frees allocated areas.
- */
-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;
-       struct sk_buff *target_skb = NULL;
-       struct ieee80211_tx_info *info;
-       struct p54_tx_info *range;
-       u32 last_addr = priv->rx_start;
-       u32 largest_hole = 0;
-       u32 target_addr = priv->rx_start;
-       unsigned long flags;
-       unsigned int left;
-       len = (len + priv->headroom + priv->tailroom + 3) & ~0x3;
-
-       if (!skb)
-               return -EINVAL;
-
-       spin_lock_irqsave(&priv->tx_queue.lock, flags);
-
-       left = skb_queue_len(&priv->tx_queue);
-       if (unlikely(left >= 28)) {
-               /*
-                * The tx_queue is nearly full!
-                * We have throttle normal data traffic, because we must
-                * have a few spare slots for control frames left.
-                */
-               ieee80211_stop_queues(dev);
-               queue_delayed_work(dev->workqueue, &priv->work,
-                                  msecs_to_jiffies(P54_TX_TIMEOUT));
-
-               if (unlikely(left == 32)) {
-                       /*
-                        * The tx_queue is now really full.
-                        *
-                        * TODO: check if the device has crashed and reset it.
-                        */
-                       spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
-                       return -ENOSPC;
-               }
-       }
-
-       entry = priv->tx_queue.next;
-       while (left--) {
-               u32 hole_size;
-               info = IEEE80211_SKB_CB(entry);
-               range = (void *)info->rate_driver_data;
-               hole_size = range->start_addr - last_addr;
-               if (!target_skb && hole_size >= len) {
-                       target_skb = entry->prev;
-                       hole_size -= len;
-                       target_addr = last_addr;
-               }
-               largest_hole = max(largest_hole, hole_size);
-               last_addr = range->end_addr;
-               entry = entry->next;
-       }
-       if (!target_skb && priv->rx_end - last_addr >= len) {
-               target_skb = priv->tx_queue.prev;
-               largest_hole = max(largest_hole, priv->rx_end - last_addr - len);
-               if (!skb_queue_empty(&priv->tx_queue)) {
-                       info = IEEE80211_SKB_CB(target_skb);
-                       range = (void *)info->rate_driver_data;
-                       target_addr = range->end_addr;
-               }
-       } else
-               largest_hole = max(largest_hole, priv->rx_end - last_addr);
-
-       if (!target_skb) {
-               spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
-               ieee80211_stop_queues(dev);
-               return -ENOSPC;
-       }
-
-       info = IEEE80211_SKB_CB(skb);
-       range = (void *)info->rate_driver_data;
-       range->start_addr = target_addr;
-       range->end_addr = target_addr + len;
-       __skb_queue_after(&priv->tx_queue, target_skb, skb);
-       spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
-
-       if (largest_hole < priv->headroom + sizeof(struct p54_hdr) +
-                          48 + IEEE80211_MAX_RTS_THRESHOLD + priv->tailroom)
-               ieee80211_stop_queues(dev);
-
-       data->req_id = cpu_to_le32(target_addr + priv->headroom);
-       return 0;
-}
-
-static struct sk_buff *p54_alloc_skb(struct ieee80211_hw *dev, u16 hdr_flags,
-                                    u16 payload_len, u16 type, gfp_t memflags)
-{
-       struct p54_common *priv = dev->priv;
-       struct p54_hdr *hdr;
-       struct sk_buff *skb;
-       size_t frame_len = sizeof(*hdr) + payload_len;
-
-       if (frame_len > P54_MAX_CTRL_FRAME_LEN)
-               return NULL;
-
-       skb = __dev_alloc_skb(priv->tx_hdr_len + frame_len, memflags);
-       if (!skb)
-               return NULL;
-       skb_reserve(skb, priv->tx_hdr_len);
-
-       hdr = (struct p54_hdr *) skb_put(skb, sizeof(*hdr));
-       hdr->flags = cpu_to_le16(hdr_flags);
-       hdr->len = cpu_to_le16(payload_len);
-       hdr->type = cpu_to_le16(type);
-       hdr->tries = hdr->rts_tries = 0;
-
-       if (p54_assign_address(dev, skb, hdr, frame_len)) {
-               kfree_skb(skb);
-               return NULL;
-       }
-       return skb;
-}
-
-int p54_read_eeprom(struct ieee80211_hw *dev)
-{
-       struct p54_common *priv = dev->priv;
-       struct p54_eeprom_lm86 *eeprom_hdr;
-       struct sk_buff *skb;
-       size_t eeprom_size = 0x2020, offset = 0, blocksize, maxblocksize;
-       int ret = -ENOMEM;
-       void *eeprom = NULL;
-
-       maxblocksize = EEPROM_READBACK_LEN;
-       if (priv->fw_var >= 0x509)
-               maxblocksize -= 0xc;
-       else
-               maxblocksize -= 0x4;
-
-       skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL, sizeof(*eeprom_hdr) +
-                           maxblocksize, P54_CONTROL_TYPE_EEPROM_READBACK,
-                           GFP_KERNEL);
-       if (!skb)
-               goto free;
-       priv->eeprom = kzalloc(EEPROM_READBACK_LEN, GFP_KERNEL);
-       if (!priv->eeprom)
-               goto free;
-       eeprom = kzalloc(eeprom_size, GFP_KERNEL);
-       if (!eeprom)
-               goto free;
-
-       eeprom_hdr = (struct p54_eeprom_lm86 *) skb_put(skb,
-                    sizeof(*eeprom_hdr) + maxblocksize);
-
-       while (eeprom_size) {
-               blocksize = min(eeprom_size, maxblocksize);
-               if (priv->fw_var < 0x509) {
-                       eeprom_hdr->v1.offset = cpu_to_le16(offset);
-                       eeprom_hdr->v1.len = cpu_to_le16(blocksize);
-               } else {
-                       eeprom_hdr->v2.offset = cpu_to_le32(offset);
-                       eeprom_hdr->v2.len = cpu_to_le16(blocksize);
-                       eeprom_hdr->v2.magic2 = 0xf;
-                       memcpy(eeprom_hdr->v2.magic, (const char *)"LOCK", 4);
-               }
-               priv->tx(dev, skb);
-
-               if (!wait_for_completion_interruptible_timeout(&priv->eeprom_comp, HZ)) {
-                       printk(KERN_ERR "%s: device does not respond!\n",
-                               wiphy_name(dev->wiphy));
-                       ret = -EBUSY;
-                       goto free;
-               }
-
-               memcpy(eeprom + offset, priv->eeprom, blocksize);
-               offset += blocksize;
-               eeprom_size -= blocksize;
-       }
-
-       ret = p54_parse_eeprom(dev, eeprom, offset);
-free:
-       kfree(priv->eeprom);
-       priv->eeprom = NULL;
-       p54_free_skb(dev, skb);
-       kfree(eeprom);
-
-       return ret;
-}
-EXPORT_SYMBOL_GPL(p54_read_eeprom);
-
-static int p54_set_tim(struct ieee80211_hw *dev, struct ieee80211_sta *sta,
-               bool set)
-{
-       struct p54_common *priv = dev->priv;
-       struct sk_buff *skb;
-       struct p54_tim *tim;
-
-       skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*tim),
-                           P54_CONTROL_TYPE_TIM, GFP_ATOMIC);
-       if (!skb)
-               return -ENOMEM;
-
-       tim = (struct p54_tim *) skb_put(skb, sizeof(*tim));
-       tim->count = 1;
-       tim->entry[0] = cpu_to_le16(set ? (sta->aid | 0x8000) : sta->aid);
-       priv->tx(dev, skb);
-       return 0;
-}
-
-static int p54_sta_unlock(struct ieee80211_hw *dev, u8 *addr)
-{
-       struct p54_common *priv = dev->priv;
-       struct sk_buff *skb;
-       struct p54_sta_unlock *sta;
-
-       skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*sta),
-                           P54_CONTROL_TYPE_PSM_STA_UNLOCK, GFP_ATOMIC);
-       if (!skb)
-               return -ENOMEM;
-
-       sta = (struct p54_sta_unlock *)skb_put(skb, sizeof(*sta));
-       memcpy(sta->addr, addr, ETH_ALEN);
-       priv->tx(dev, skb);
-       return 0;
-}
-
-static void p54_sta_notify(struct ieee80211_hw *dev, struct ieee80211_vif *vif,
-                             enum sta_notify_cmd notify_cmd,
-                             struct ieee80211_sta *sta)
-{
-       switch (notify_cmd) {
-       case STA_NOTIFY_ADD:
-       case STA_NOTIFY_REMOVE:
-               /*
-                * Notify the firmware that we don't want or we don't
-                * need to buffer frames for this station anymore.
-                */
-
-               p54_sta_unlock(dev, sta->addr);
-               break;
-       case STA_NOTIFY_AWAKE:
-               /* update the firmware's filter table */
-               p54_sta_unlock(dev, sta->addr);
-               break;
-       default:
-               break;
-       }
-}
-
-static int p54_tx_cancel(struct ieee80211_hw *dev, struct sk_buff *entry)
-{
-       struct p54_common *priv = dev->priv;
-       struct sk_buff *skb;
-       struct p54_hdr *hdr;
-       struct p54_txcancel *cancel;
-
-       skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*cancel),
-                           P54_CONTROL_TYPE_TXCANCEL, GFP_ATOMIC);
-       if (!skb)
-               return -ENOMEM;
-
-       hdr = (void *)entry->data;
-       cancel = (struct p54_txcancel *)skb_put(skb, sizeof(*cancel));
-       cancel->req_id = hdr->req_id;
-       priv->tx(dev, skb);
-       return 0;
-}
-
-static int p54_tx_fill(struct ieee80211_hw *dev, struct sk_buff *skb,
-               struct ieee80211_tx_info *info, u8 *queue, size_t *extra_len,
-               u16 *flags, u16 *aid)
-{
-       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
-       struct p54_common *priv = dev->priv;
-       int ret = 1;
-
-       switch (priv->mode) {
-       case NL80211_IFTYPE_MONITOR:
-               /*
-                * We have to set P54_HDR_FLAG_DATA_OUT_PROMISC for
-                * every frame in promiscuous/monitor mode.
-                * see STSW45x0C LMAC API - page 12.
-                */
-               *aid = 0;
-               *flags = P54_HDR_FLAG_DATA_OUT_PROMISC;
-               *queue += P54_QUEUE_DATA;
-               break;
-       case NL80211_IFTYPE_STATION:
-               *aid = 1;
-               if (unlikely(ieee80211_is_mgmt(hdr->frame_control))) {
-                       *queue = P54_QUEUE_MGMT;
-                       ret = 0;
-               } else
-                       *queue += P54_QUEUE_DATA;
-               break;
-       case NL80211_IFTYPE_AP:
-       case NL80211_IFTYPE_ADHOC:
-       case NL80211_IFTYPE_MESH_POINT:
-               if (info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) {
-                       *aid = 0;
-                       *queue = P54_QUEUE_CAB;
-                       return 0;
-               }
-
-               if (unlikely(ieee80211_is_mgmt(hdr->frame_control))) {
-                       if (ieee80211_is_probe_resp(hdr->frame_control)) {
-                               *aid = 0;
-                               *queue = P54_QUEUE_MGMT;
-                               *flags = P54_HDR_FLAG_DATA_OUT_TIMESTAMP |
-                                        P54_HDR_FLAG_DATA_OUT_NOCANCEL;
-                               return 0;
-                       } else if (ieee80211_is_beacon(hdr->frame_control)) {
-                               *aid = 0;
-
-                               if (info->flags & IEEE80211_TX_CTL_INJECTED) {
-                                       /*
-                                        * Injecting beacons on top of a AP is
-                                        * not a good idea... nevertheless,
-                                        * it should be doable.
-                                        */
-
-                                       *queue += P54_QUEUE_DATA;
-                                       return 1;
-                               }
-
-                               *flags = P54_HDR_FLAG_DATA_OUT_TIMESTAMP;
-                               *queue = P54_QUEUE_BEACON;
-                               *extra_len = IEEE80211_MAX_TIM_LEN;
-                               return 0;
-                       } else {
-                               *queue = P54_QUEUE_MGMT;
-                               ret = 0;
-                       }
-               } else
-                       *queue += P54_QUEUE_DATA;
-
-               if (info->control.sta)
-                       *aid = info->control.sta->aid;
-
-               if (info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT)
-                       *flags |= P54_HDR_FLAG_DATA_OUT_NOCANCEL;
-               break;
-       }
-       return ret;
-}
-
-static u8 p54_convert_algo(enum ieee80211_key_alg alg)
-{
-       switch (alg) {
-       case ALG_WEP:
-               return P54_CRYPTO_WEP;
-       case ALG_TKIP:
-               return P54_CRYPTO_TKIPMICHAEL;
-       case ALG_CCMP:
-               return P54_CRYPTO_AESCCMP;
-       default:
-               return 0;
-       }
-}
-
-static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
-{
-       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
-       struct ieee80211_tx_queue_stats *current_queue;
-       struct p54_common *priv = dev->priv;
-       struct p54_hdr *hdr;
-       struct p54_tx_data *txhdr;
-       size_t padding, len, tim_len = 0;
-       int i, j, ridx, ret;
-       u16 hdr_flags = 0, aid = 0;
-       u8 rate, queue, crypt_offset = 0;
-       u8 cts_rate = 0x20;
-       u8 rc_flags;
-       u8 calculated_tries[4];
-       u8 nrates = 0, nremaining = 8;
-
-       queue = skb_get_queue_mapping(skb);
-
-       ret = p54_tx_fill(dev, skb, info, &queue, &tim_len, &hdr_flags, &aid);
-       current_queue = &priv->tx_stats[queue];
-       if (unlikely((current_queue->len > current_queue->limit) && ret))
-               return NETDEV_TX_BUSY;
-       current_queue->len++;
-       current_queue->count++;
-       if ((current_queue->len == current_queue->limit) && ret)
-               ieee80211_stop_queue(dev, skb_get_queue_mapping(skb));
-
-       padding = (unsigned long)(skb->data - (sizeof(*hdr) + sizeof(*txhdr))) & 3;
-       len = skb->len;
-
-       if (info->control.hw_key) {
-               crypt_offset = ieee80211_get_hdrlen_from_skb(skb);
-               if (info->control.hw_key->alg == ALG_TKIP) {
-                       u8 *iv = (u8 *)(skb->data + crypt_offset);
-                       /*
-                        * The firmware excepts that the IV has to have
-                        * this special format
-                        */
-                       iv[1] = iv[0];
-                       iv[0] = iv[2];
-                       iv[2] = 0;
-               }
-       }
-
-       txhdr = (struct p54_tx_data *) skb_push(skb, sizeof(*txhdr) + padding);
-       hdr = (struct p54_hdr *) skb_push(skb, sizeof(*hdr));
-
-       if (padding)
-               hdr_flags |= P54_HDR_FLAG_DATA_ALIGN;
-       hdr->type = cpu_to_le16(aid);
-       hdr->rts_tries = info->control.rates[0].count;
-
-       /*
-        * we register the rates in perfect order, and
-        * RTS/CTS won't happen on 5 GHz
-        */
-       cts_rate = info->control.rts_cts_rate_idx;
-
-       memset(&txhdr->rateset, 0, sizeof(txhdr->rateset));
-
-       /* see how many rates got used */
-       for (i = 0; i < 4; i++) {
-               if (info->control.rates[i].idx < 0)
-                       break;
-               nrates++;
-       }
-
-       /* limit tries to 8/nrates per rate */
-       for (i = 0; i < nrates; i++) {
-               /*
-                * The magic expression here is equivalent to 8/nrates for
-                * all values that matter, but avoids division and jumps.
-                * Note that nrates can only take the values 1 through 4.
-                */
-               calculated_tries[i] = min_t(int, ((15 >> nrates) | 1) + 1,
-                                                info->control.rates[i].count);
-               nremaining -= calculated_tries[i];
-       }
-
-       /* if there are tries left, distribute from back to front */
-       for (i = nrates - 1; nremaining > 0 && i >= 0; i--) {
-               int tmp = info->control.rates[i].count - calculated_tries[i];
-
-               if (tmp <= 0)
-                       continue;
-               /* RC requested more tries at this rate */
-
-               tmp = min_t(int, tmp, nremaining);
-               calculated_tries[i] += tmp;
-               nremaining -= tmp;
-       }
-
-       ridx = 0;
-       for (i = 0; i < nrates && ridx < 8; i++) {
-               /* we register the rates in perfect order */
-               rate = info->control.rates[i].idx;
-               if (info->band == IEEE80211_BAND_5GHZ)
-                       rate += 4;
-
-               /* store the count we actually calculated for TX status */
-               info->control.rates[i].count = calculated_tries[i];
-
-               rc_flags = info->control.rates[i].flags;
-               if (rc_flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) {
-                       rate |= 0x10;
-                       cts_rate |= 0x10;
-               }
-               if (rc_flags & IEEE80211_TX_RC_USE_RTS_CTS)
-                       rate |= 0x40;
-               else if (rc_flags & IEEE80211_TX_RC_USE_CTS_PROTECT)
-                       rate |= 0x20;
-               for (j = 0; j < calculated_tries[i] && ridx < 8; j++) {
-                       txhdr->rateset[ridx] = rate;
-                       ridx++;
-               }
-       }
-
-       if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ)
-               hdr_flags |= P54_HDR_FLAG_DATA_OUT_SEQNR;
-
-       /* TODO: enable bursting */
-       hdr->flags = cpu_to_le16(hdr_flags);
-       hdr->tries = ridx;
-       txhdr->rts_rate_idx = 0;
-       if (info->control.hw_key) {
-               txhdr->key_type = p54_convert_algo(info->control.hw_key->alg);
-               txhdr->key_len = min((u8)16, info->control.hw_key->keylen);
-               memcpy(txhdr->key, info->control.hw_key->key, txhdr->key_len);
-               if (info->control.hw_key->alg == ALG_TKIP) {
-                       if (unlikely(skb_tailroom(skb) < 12))
-                               goto err;
-                       /* reserve space for the MIC key */
-                       len += 8;
-                       memcpy(skb_put(skb, 8), &(info->control.hw_key->key
-                               [NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY]), 8);
-               }
-               /* reserve some space for ICV */
-               len += info->control.hw_key->icv_len;
-               memset(skb_put(skb, info->control.hw_key->icv_len), 0,
-                      info->control.hw_key->icv_len);
-       } else {
-               txhdr->key_type = 0;
-               txhdr->key_len = 0;
-       }
-       txhdr->crypt_offset = crypt_offset;
-       txhdr->hw_queue = queue;
-       txhdr->backlog = current_queue->len;
-       memset(txhdr->durations, 0, sizeof(txhdr->durations));
-       txhdr->tx_antenna = ((info->antenna_sel_tx == 0) ?
-               2 : info->antenna_sel_tx - 1) & priv->tx_diversity_mask;
-       if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW) {
-               txhdr->longbow.cts_rate = cts_rate;
-               txhdr->longbow.output_power = cpu_to_le16(priv->output_power);
-       } else {
-               txhdr->normal.output_power = priv->output_power;
-               txhdr->normal.cts_rate = cts_rate;
-       }
-       if (padding)
-               txhdr->align[0] = padding;
-
-       hdr->len = cpu_to_le16(len);
-       /* modifies skb->cb and with it info, so must be last! */
-       if (unlikely(p54_assign_address(dev, skb, hdr, skb->len + tim_len)))
-               goto err;
-       priv->tx(dev, skb);
-
-       queue_delayed_work(dev->workqueue, &priv->work,
-                          msecs_to_jiffies(P54_TX_FRAME_LIFETIME));
-
-       return NETDEV_TX_OK;
-
- err:
-       skb_pull(skb, sizeof(*hdr) + sizeof(*txhdr) + padding);
-       current_queue->len--;
-       current_queue->count--;
-       return NETDEV_TX_BUSY;
-}
-
-static int p54_setup_mac(struct ieee80211_hw *dev)
-{
-       struct p54_common *priv = dev->priv;
-       struct sk_buff *skb;
-       struct p54_setup_mac *setup;
-       u16 mode;
-
-       skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*setup),
-                           P54_CONTROL_TYPE_SETUP, GFP_ATOMIC);
-       if (!skb)
-               return -ENOMEM;
-
-       setup = (struct p54_setup_mac *) skb_put(skb, sizeof(*setup));
-       if (dev->conf.radio_enabled) {
-               switch (priv->mode) {
-               case NL80211_IFTYPE_STATION:
-                       mode = P54_FILTER_TYPE_STATION;
-                       break;
-               case NL80211_IFTYPE_AP:
-                       mode = P54_FILTER_TYPE_AP;
-                       break;
-               case NL80211_IFTYPE_ADHOC:
-               case NL80211_IFTYPE_MESH_POINT:
-                       mode = P54_FILTER_TYPE_IBSS;
-                       break;
-               case NL80211_IFTYPE_MONITOR:
-                       mode = P54_FILTER_TYPE_PROMISCUOUS;
-                       break;
-               default:
-                       mode = P54_FILTER_TYPE_HIBERNATE;
-                       break;
-               }
-
-               /*
-                * "TRANSPARENT and PROMISCUOUS are mutually exclusive"
-                * STSW45X0C LMAC API - page 12
-                */
-               if (((priv->filter_flags & FIF_PROMISC_IN_BSS) ||
-                    (priv->filter_flags & FIF_OTHER_BSS)) &&
-                   (mode != P54_FILTER_TYPE_PROMISCUOUS))
-                       mode |= P54_FILTER_TYPE_TRANSPARENT;
-       } else
-               mode = P54_FILTER_TYPE_HIBERNATE;
-
-       setup->mac_mode = cpu_to_le16(mode);
-       memcpy(setup->mac_addr, priv->mac_addr, ETH_ALEN);
-       memcpy(setup->bssid, priv->bssid, ETH_ALEN);
-       setup->rx_antenna = 2 & priv->rx_diversity_mask; /* automatic */
-       setup->rx_align = 0;
-       if (priv->fw_var < 0x500) {
-               setup->v1.basic_rate_mask = cpu_to_le32(priv->basic_rate_mask);
-               memset(setup->v1.rts_rates, 0, 8);
-               setup->v1.rx_addr = cpu_to_le32(priv->rx_end);
-               setup->v1.max_rx = cpu_to_le16(priv->rx_mtu);
-               setup->v1.rxhw = cpu_to_le16(priv->rxhw);
-               setup->v1.wakeup_timer = cpu_to_le16(priv->wakeup_timer);
-               setup->v1.unalloc0 = cpu_to_le16(0);
-       } else {
-               setup->v2.rx_addr = cpu_to_le32(priv->rx_end);
-               setup->v2.max_rx = cpu_to_le16(priv->rx_mtu);
-               setup->v2.rxhw = cpu_to_le16(priv->rxhw);
-               setup->v2.timer = cpu_to_le16(priv->wakeup_timer);
-               setup->v2.truncate = cpu_to_le16(48896);
-               setup->v2.basic_rate_mask = cpu_to_le32(priv->basic_rate_mask);
-               setup->v2.sbss_offset = 0;
-               setup->v2.mcast_window = 0;
-               setup->v2.rx_rssi_threshold = 0;
-               setup->v2.rx_ed_threshold = 0;
-               setup->v2.ref_clock = cpu_to_le32(644245094);
-               setup->v2.lpf_bandwidth = cpu_to_le16(65535);
-               setup->v2.osc_start_delay = cpu_to_le16(65535);
-       }
-       priv->tx(dev, skb);
-       return 0;
-}
-
-static int p54_scan(struct ieee80211_hw *dev, u16 mode, u16 dwell)
-{
-       struct p54_common *priv = dev->priv;
-       struct sk_buff *skb;
-       struct p54_hdr *hdr;
-       struct p54_scan_head *head;
-       struct p54_iq_autocal_entry *iq_autocal;
-       union p54_scan_body_union *body;
-       struct p54_scan_tail_rate *rate;
-       struct pda_rssi_cal_entry *rssi;
-       unsigned int i;
-       void *entry;
-       int band = dev->conf.channel->band;
-       __le16 freq = cpu_to_le16(dev->conf.channel->center_freq);
-
-       skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*head) +
-                           2 + sizeof(*iq_autocal) + sizeof(*body) +
-                           sizeof(*rate) + 2 * sizeof(*rssi),
-                           P54_CONTROL_TYPE_SCAN, GFP_ATOMIC);
-       if (!skb)
-               return -ENOMEM;
-
-       head = (struct p54_scan_head *) skb_put(skb, sizeof(*head));
-       memset(head->scan_params, 0, sizeof(head->scan_params));
-       head->mode = cpu_to_le16(mode);
-       head->dwell = cpu_to_le16(dwell);
-       head->freq = freq;
-
-       if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW) {
-               __le16 *pa_power_points = (__le16 *) skb_put(skb, 2);
-               *pa_power_points = cpu_to_le16(0x0c);
-       }
-
-       iq_autocal = (void *) skb_put(skb, sizeof(*iq_autocal));
-       for (i = 0; i < priv->iq_autocal_len; i++) {
-               if (priv->iq_autocal[i].freq != freq)
-                       continue;
-
-               memcpy(iq_autocal, &priv->iq_autocal[i].params,
-                      sizeof(struct p54_iq_autocal_entry));
-               break;
-       }
-       if (i == priv->iq_autocal_len)
-               goto err;
-
-       if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW)
-               body = (void *) skb_put(skb, sizeof(body->longbow));
-       else
-               body = (void *) skb_put(skb, sizeof(body->normal));
-
-       for (i = 0; i < priv->output_limit->entries; i++) {
-               __le16 *entry_freq = (void *) (priv->output_limit->data +
-                                    priv->output_limit->entry_size * i);
-
-               if (*entry_freq != freq)
-                       continue;
-
-               if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW) {
-                       memcpy(&body->longbow.power_limits,
-                              (void *) entry_freq + sizeof(__le16),
-                              priv->output_limit->entry_size);
-               } else {
-                       struct pda_channel_output_limit *limits =
-                              (void *) entry_freq;
-
-                       body->normal.val_barker = 0x38;
-                       body->normal.val_bpsk = body->normal.dup_bpsk =
-                               limits->val_bpsk;
-                       body->normal.val_qpsk = body->normal.dup_qpsk =
-                               limits->val_qpsk;
-                       body->normal.val_16qam = body->normal.dup_16qam =
-                               limits->val_16qam;
-                       body->normal.val_64qam = body->normal.dup_64qam =
-                               limits->val_64qam;
-               }
-               break;
-       }
-       if (i == priv->output_limit->entries)
-               goto err;
-
-       entry = (void *)(priv->curve_data->data + priv->curve_data->offset);
-       for (i = 0; i < priv->curve_data->entries; i++) {
-               if (*((__le16 *)entry) != freq) {
-                       entry += priv->curve_data->entry_size;
-                       continue;
-               }
-
-               if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW) {
-                       memcpy(&body->longbow.curve_data,
-                               (void *) entry + sizeof(__le16),
-                               priv->curve_data->entry_size);
-               } else {
-                       struct p54_scan_body *chan = &body->normal;
-                       struct pda_pa_curve_data *curve_data =
-                               (void *) priv->curve_data->data;
-
-                       entry += sizeof(__le16);
-                       chan->pa_points_per_curve = 8;
-                       memset(chan->curve_data, 0, sizeof(*chan->curve_data));
-                       memcpy(chan->curve_data, entry,
-                              sizeof(struct p54_pa_curve_data_sample) *
-                              min((u8)8, curve_data->points_per_channel));
-               }
-               break;
-       }
-       if (i == priv->curve_data->entries)
-               goto err;
-
-       if ((priv->fw_var >= 0x500) && (priv->fw_var < 0x509)) {
-               rate = (void *) skb_put(skb, sizeof(*rate));
-               rate->basic_rate_mask = cpu_to_le32(priv->basic_rate_mask);
-               for (i = 0; i < sizeof(rate->rts_rates); i++)
-                       rate->rts_rates[i] = i;
-       }
-
-       rssi = (struct pda_rssi_cal_entry *) skb_put(skb, sizeof(*rssi));
-       rssi->mul = cpu_to_le16(priv->rssical_db[band].mul);
-       rssi->add = cpu_to_le16(priv->rssical_db[band].add);
-       if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW) {
-               /* Longbow frontend needs ever more */
-               rssi = (void *) skb_put(skb, sizeof(*rssi));
-               rssi->mul = cpu_to_le16(priv->rssical_db[band].longbow_unkn);
-               rssi->add = cpu_to_le16(priv->rssical_db[band].longbow_unk2);
-       }
-
-       if (priv->fw_var >= 0x509) {
-               rate = (void *) skb_put(skb, sizeof(*rate));
-               rate->basic_rate_mask = cpu_to_le32(priv->basic_rate_mask);
-               for (i = 0; i < sizeof(rate->rts_rates); i++)
-                       rate->rts_rates[i] = i;
-       }
-
-       hdr = (struct p54_hdr *) skb->data;
-       hdr->len = cpu_to_le16(skb->len - sizeof(*hdr));
-
-       priv->tx(dev, skb);
-       return 0;
-
- err:
-       printk(KERN_ERR "%s: frequency change failed\n", wiphy_name(dev->wiphy));
-       p54_free_skb(dev, skb);
-       return -EINVAL;
-}
-
-static int p54_set_leds(struct ieee80211_hw *dev)
-{
-       struct p54_common *priv = dev->priv;
-       struct sk_buff *skb;
-       struct p54_led *led;
-
-       skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*led),
-                           P54_CONTROL_TYPE_LED, GFP_ATOMIC);
-       if (!skb)
-               return -ENOMEM;
-
-       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;
-}
-
-#define P54_SET_QUEUE(queue, ai_fs, cw_min, cw_max, _txop)     \
-do {                                                           \
-       queue.aifs = cpu_to_le16(ai_fs);                        \
-       queue.cwmin = cpu_to_le16(cw_min);                      \
-       queue.cwmax = cpu_to_le16(cw_max);                      \
-       queue.txop = cpu_to_le16(_txop);                        \
-} while(0)
-
-static int p54_set_edcf(struct ieee80211_hw *dev)
-{
-       struct p54_common *priv = dev->priv;
-       struct sk_buff *skb;
-       struct p54_edcf *edcf;
-
-       skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*edcf),
-                           P54_CONTROL_TYPE_DCFINIT, GFP_ATOMIC);
-       if (!skb)
-               return -ENOMEM;
-
-       edcf = (struct p54_edcf *)skb_put(skb, sizeof(*edcf));
-       if (priv->use_short_slot) {
-               edcf->slottime = 9;
-               edcf->sifs = 0x10;
-               edcf->eofpad = 0x00;
-       } else {
-               edcf->slottime = 20;
-               edcf->sifs = 0x0a;
-               edcf->eofpad = 0x06;
-       }
-       /* (see prism54/isl_oid.h for further details) */
-       edcf->frameburst = cpu_to_le16(0);
-       edcf->round_trip_delay = cpu_to_le16(0);
-       edcf->flags = 0;
-       memset(edcf->mapping, 0, sizeof(edcf->mapping));
-       memcpy(edcf->queue, priv->qos_params, sizeof(edcf->queue));
-       priv->tx(dev, skb);
-       return 0;
-}
-
-static int p54_set_ps(struct ieee80211_hw *dev)
-{
-       struct p54_common *priv = dev->priv;
-       struct sk_buff *skb;
-       struct p54_psm *psm;
-       u16 mode;
-       int i;
-
-       if (dev->conf.flags & IEEE80211_CONF_PS)
-               mode = P54_PSM | P54_PSM_BEACON_TIMEOUT | P54_PSM_DTIM |
-                      P54_PSM_CHECKSUM | P54_PSM_MCBC;
-       else
-               mode = P54_PSM_CAM;
-
-       skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*psm),
-                           P54_CONTROL_TYPE_PSM, GFP_ATOMIC);
-       if (!skb)
-               return -ENOMEM;
-
-       psm = (struct p54_psm *)skb_put(skb, sizeof(*psm));
-       psm->mode = cpu_to_le16(mode);
-       psm->aid = cpu_to_le16(priv->aid);
-       for (i = 0; i < ARRAY_SIZE(psm->intervals); i++) {
-               psm->intervals[i].interval =
-                       cpu_to_le16(dev->conf.listen_interval);
-               psm->intervals[i].periods = cpu_to_le16(1);
-       }
-
-       psm->beacon_rssi_skip_max = 200;
-       psm->rssi_delta_threshold = 0;
-       psm->nr = 10;
-       psm->exclude[0] = 0;
-
-       priv->tx(dev, skb);
-
-       return 0;
-}
-
-static int p54_beacon_tim(struct sk_buff *skb)
-{
-       /*
-        * the good excuse for this mess is ... the firmware.
-        * The dummy TIM MUST be at the end of the beacon frame,
-        * because it'll be overwritten!
-        */
-
-       struct ieee80211_mgmt *mgmt = (void *)skb->data;
-       u8 *pos, *end;
-
-       if (skb->len <= sizeof(mgmt))
-               return -EINVAL;
-
-       pos = (u8 *)mgmt->u.beacon.variable;
-       end = skb->data + skb->len;
-       while (pos < end) {
-               if (pos + 2 + pos[1] > end)
-                       return -EINVAL;
-
-               if (pos[0] == WLAN_EID_TIM) {
-                       u8 dtim_len = pos[1];
-                       u8 dtim_period = pos[3];
-                       u8 *next = pos + 2 + dtim_len;
-
-                       if (dtim_len < 3)
-                               return -EINVAL;
-
-                       memmove(pos, next, end - next);
-
-                       if (dtim_len > 3)
-                               skb_trim(skb, skb->len - (dtim_len - 3));
-
-                       pos = end - (dtim_len + 2);
-
-                       /* add the dummy at the end */
-                       pos[0] = WLAN_EID_TIM;
-                       pos[1] = 3;
-                       pos[2] = 0;
-                       pos[3] = dtim_period;
-                       pos[4] = 0;
-                       return 0;
-               }
-               pos += 2 + pos[1];
-       }
-       return 0;
-}
-
-static int p54_beacon_update(struct ieee80211_hw *dev,
-                       struct ieee80211_vif *vif)
-{
-       struct p54_common *priv = dev->priv;
-       struct sk_buff *beacon;
-       int ret;
-
-       if (priv->cached_beacon) {
-               p54_tx_cancel(dev, priv->cached_beacon);
-               /* wait for the last beacon the be freed */
-               msleep(10);
-       }
-
-       beacon = ieee80211_beacon_get(dev, vif);
-       if (!beacon)
-               return -ENOMEM;
-       ret = p54_beacon_tim(beacon);
-       if (ret)
-               return ret;
-       ret = p54_tx(dev, beacon);
-       if (ret)
-               return ret;
-       priv->cached_beacon = beacon;
-       priv->tsf_high32 = 0;
-       priv->tsf_low32 = 0;
-
-       return 0;
-}
-
-static int p54_start(struct ieee80211_hw *dev)
-{
-       struct p54_common *priv = dev->priv;
-       int err;
-
-       mutex_lock(&priv->conf_mutex);
-       err = priv->open(dev);
-       if (err)
-               goto out;
-       P54_SET_QUEUE(priv->qos_params[0], 0x0002, 0x0003, 0x0007, 47);
-       P54_SET_QUEUE(priv->qos_params[1], 0x0002, 0x0007, 0x000f, 94);
-       P54_SET_QUEUE(priv->qos_params[2], 0x0003, 0x000f, 0x03ff, 0);
-       P54_SET_QUEUE(priv->qos_params[3], 0x0007, 0x000f, 0x03ff, 0);
-       err = p54_set_edcf(dev);
-       if (err)
-               goto out;
-
-       memset(priv->bssid, ~0, ETH_ALEN);
-       priv->mode = NL80211_IFTYPE_MONITOR;
-       err = p54_setup_mac(dev);
-       if (err) {
-               priv->mode = NL80211_IFTYPE_UNSPECIFIED;
-               goto out;
-       }
-
-       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;
-}
-
-static void p54_stop(struct ieee80211_hw *dev)
-{
-       struct p54_common *priv = dev->priv;
-       struct sk_buff *skb;
-
-       mutex_lock(&priv->conf_mutex);
-       priv->mode = NL80211_IFTYPE_UNSPECIFIED;
-       priv->softled_state = 0;
-       p54_set_leds(dev);
-
-#ifdef CONFIG_P54_LEDS
-       cancel_delayed_work_sync(&priv->led_work);
-#endif /* CONFIG_P54_LEDS */
-       cancel_delayed_work_sync(&priv->work);
-       if (priv->cached_beacon)
-               p54_tx_cancel(dev, priv->cached_beacon);
-
-       priv->stop(dev);
-       while ((skb = skb_dequeue(&priv->tx_queue)))
-               kfree_skb(skb);
-       priv->cached_beacon = NULL;
-       priv->tsf_high32 = priv->tsf_low32 = 0;
-       mutex_unlock(&priv->conf_mutex);
-}
-
-static int p54_add_interface(struct ieee80211_hw *dev,
-                            struct ieee80211_if_init_conf *conf)
-{
-       struct p54_common *priv = dev->priv;
-
-       mutex_lock(&priv->conf_mutex);
-       if (priv->mode != NL80211_IFTYPE_MONITOR) {
-               mutex_unlock(&priv->conf_mutex);
-               return -EOPNOTSUPP;
-       }
-
-       priv->vif = conf->vif;
-
-       switch (conf->type) {
-       case NL80211_IFTYPE_STATION:
-       case NL80211_IFTYPE_ADHOC:
-       case NL80211_IFTYPE_AP:
-       case NL80211_IFTYPE_MESH_POINT:
-               priv->mode = conf->type;
-               break;
-       default:
-               mutex_unlock(&priv->conf_mutex);
-               return -EOPNOTSUPP;
-       }
-
-       memcpy(priv->mac_addr, conf->mac_addr, ETH_ALEN);
-       p54_setup_mac(dev);
-       mutex_unlock(&priv->conf_mutex);
-       return 0;
-}
-
-static void p54_remove_interface(struct ieee80211_hw *dev,
-                                struct ieee80211_if_init_conf *conf)
-{
-       struct p54_common *priv = dev->priv;
-
-       mutex_lock(&priv->conf_mutex);
-       priv->vif = NULL;
-       if (priv->cached_beacon)
-               p54_tx_cancel(dev, priv->cached_beacon);
-       priv->mode = NL80211_IFTYPE_MONITOR;
-       memset(priv->mac_addr, 0, ETH_ALEN);
-       memset(priv->bssid, 0, ETH_ALEN);
-       p54_setup_mac(dev);
-       mutex_unlock(&priv->conf_mutex);
-}
-
-static int p54_config(struct ieee80211_hw *dev, u32 changed)
-{
-       int ret = 0;
-       struct p54_common *priv = dev->priv;
-       struct ieee80211_conf *conf = &dev->conf;
-
-       mutex_lock(&priv->conf_mutex);
-       if (changed & IEEE80211_CONF_CHANGE_POWER)
-               priv->output_power = conf->power_level << 2;
-       if (changed & IEEE80211_CONF_CHANGE_RADIO_ENABLED) {
-               ret = p54_setup_mac(dev);
-               if (ret)
-                       goto out;
-       }
-       if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
-               ret = p54_scan(dev, P54_SCAN_EXIT, 0);
-               if (ret)
-                       goto out;
-       }
-       if (changed & IEEE80211_CONF_CHANGE_PS) {
-               ret = p54_set_ps(dev);
-               if (ret)
-                       goto out;
-       }
-
-out:
-       mutex_unlock(&priv->conf_mutex);
-       return ret;
-}
-
-static void p54_configure_filter(struct ieee80211_hw *dev,
-                                unsigned int changed_flags,
-                                unsigned int *total_flags,
-                                int mc_count, struct dev_mc_list *mclist)
-{
-       struct p54_common *priv = dev->priv;
-
-       *total_flags &= FIF_PROMISC_IN_BSS |
-                       FIF_OTHER_BSS;
-
-       priv->filter_flags = *total_flags;
-
-       if (changed_flags & (FIF_PROMISC_IN_BSS | FIF_OTHER_BSS))
-               p54_setup_mac(dev);
-}
-
-static int p54_conf_tx(struct ieee80211_hw *dev, u16 queue,
-                      const struct ieee80211_tx_queue_params *params)
-{
-       struct p54_common *priv = dev->priv;
-       int ret;
-
-       mutex_lock(&priv->conf_mutex);
-       if ((params) && !(queue > 4)) {
-               P54_SET_QUEUE(priv->qos_params[queue], params->aifs,
-                       params->cw_min, params->cw_max, params->txop);
-               ret = p54_set_edcf(dev);
-       } else
-               ret = -EINVAL;
-       mutex_unlock(&priv->conf_mutex);
-       return ret;
-}
-
-static int p54_init_xbow_synth(struct ieee80211_hw *dev)
-{
-       struct p54_common *priv = dev->priv;
-       struct sk_buff *skb;
-       struct p54_xbow_synth *xbow;
-
-       skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*xbow),
-                           P54_CONTROL_TYPE_XBOW_SYNTH_CFG, GFP_KERNEL);
-       if (!skb)
-               return -ENOMEM;
-
-       xbow = (struct p54_xbow_synth *)skb_put(skb, sizeof(*xbow));
-       xbow->magic1 = cpu_to_le16(0x1);
-       xbow->magic2 = cpu_to_le16(0x2);
-       xbow->freq = cpu_to_le16(5390);
-       memset(xbow->padding, 0, sizeof(xbow->padding));
-       priv->tx(dev, skb);
-       return 0;
-}
-
-static void p54_work(struct work_struct *work)
-{
-       struct p54_common *priv = container_of(work, struct p54_common,
-                                              work.work);
-       struct ieee80211_hw *dev = priv->hw;
-       struct sk_buff *skb;
-
-       if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED))
-               return ;
-
-       /*
-        * TODO: walk through tx_queue and do the following tasks
-        *      1. initiate bursts.
-        *      2. cancel stuck frames / reset the device if necessary.
-        */
-
-       skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL,
-                           sizeof(struct p54_statistics),
-                           P54_CONTROL_TYPE_STAT_READBACK, GFP_KERNEL);
-       if (!skb)
-               return ;
-
-       priv->tx(dev, skb);
-}
-
-static int p54_get_stats(struct ieee80211_hw *dev,
-                        struct ieee80211_low_level_stats *stats)
-{
-       struct p54_common *priv = dev->priv;
-
-       memcpy(stats, &priv->stats, sizeof(*stats));
-       return 0;
-}
-
-static int p54_get_tx_stats(struct ieee80211_hw *dev,
-                           struct ieee80211_tx_queue_stats *stats)
-{
-       struct p54_common *priv = dev->priv;
-
-       memcpy(stats, &priv->tx_stats[P54_QUEUE_DATA],
-              sizeof(stats[0]) * dev->queues);
-       return 0;
-}
-
-static void p54_bss_info_changed(struct ieee80211_hw *dev,
-                                struct ieee80211_vif *vif,
-                                struct ieee80211_bss_conf *info,
-                                u32 changed)
-{
-       struct p54_common *priv = dev->priv;
-       int ret;
-
-       mutex_lock(&priv->conf_mutex);
-       if (changed & BSS_CHANGED_BSSID) {
-               memcpy(priv->bssid, info->bssid, ETH_ALEN);
-               ret = p54_setup_mac(dev);
-               if (ret)
-                       goto out;
-       }
-
-       if (changed & BSS_CHANGED_BEACON) {
-               ret = p54_scan(dev, P54_SCAN_EXIT, 0);
-               if (ret)
-                       goto out;
-               ret = p54_setup_mac(dev);
-               if (ret)
-                       goto out;
-               ret = p54_beacon_update(dev, vif);
-               if (ret)
-                       goto out;
-       }
-       /* XXX: this mimics having two callbacks... clean up */
- out:
-       mutex_unlock(&priv->conf_mutex);
-
-       if (changed & (BSS_CHANGED_ERP_SLOT | BSS_CHANGED_BEACON)) {
-               priv->use_short_slot = info->use_short_slot;
-               p54_set_edcf(dev);
-       }
-       if (changed & BSS_CHANGED_BASIC_RATES) {
-               if (dev->conf.channel->band == IEEE80211_BAND_5GHZ)
-                       priv->basic_rate_mask = (info->basic_rates << 4);
-               else
-                       priv->basic_rate_mask = info->basic_rates;
-               p54_setup_mac(dev);
-               if (priv->fw_var >= 0x500)
-                       p54_scan(dev, P54_SCAN_EXIT, 0);
-       }
-       if (changed & BSS_CHANGED_ASSOC) {
-               if (info->assoc) {
-                       priv->aid = info->aid;
-                       priv->wakeup_timer = info->beacon_int *
-                                            info->dtim_period * 5;
-                       p54_setup_mac(dev);
-               }
-       }
-}
-
-static int p54_set_key(struct ieee80211_hw *dev, enum set_key_cmd cmd,
-                      struct ieee80211_vif *vif, struct ieee80211_sta *sta,
-                      struct ieee80211_key_conf *key)
-{
-       struct p54_common *priv = dev->priv;
-       struct sk_buff *skb;
-       struct p54_keycache *rxkey;
-       int slot, ret = 0;
-       u8 algo = 0;
-
-       if (modparam_nohwcrypt)
-               return -EOPNOTSUPP;
-
-       mutex_lock(&priv->conf_mutex);
-       if (cmd == SET_KEY) {
-               switch (key->alg) {
-               case ALG_TKIP:
-                       if (!(priv->privacy_caps & (BR_DESC_PRIV_CAP_MICHAEL |
-                             BR_DESC_PRIV_CAP_TKIP))) {
-                               ret = -EOPNOTSUPP;
-                               goto out_unlock;
-                       }
-                       key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
-                       algo = P54_CRYPTO_TKIPMICHAEL;
-                       break;
-               case ALG_WEP:
-                       if (!(priv->privacy_caps & BR_DESC_PRIV_CAP_WEP)) {
-                               ret = -EOPNOTSUPP;
-                               goto out_unlock;
-                       }
-                       key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
-                       algo = P54_CRYPTO_WEP;
-                       break;
-               case ALG_CCMP:
-                       if (!(priv->privacy_caps & BR_DESC_PRIV_CAP_AESCCMP)) {
-                               ret = -EOPNOTSUPP;
-                               goto out_unlock;
-                       }
-                       key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
-                       algo = P54_CRYPTO_AESCCMP;
-                       break;
-               default:
-                       ret = -EOPNOTSUPP;
-                       goto out_unlock;
-               }
-               slot = bitmap_find_free_region(priv->used_rxkeys,
-                                              priv->rx_keycache_size, 0);
-
-               if (slot < 0) {
-                       /*
-                        * The device supports the choosen algorithm, but the
-                        * firmware does not provide enough key slots to store
-                        * all of them.
-                        * But encryption offload for outgoing frames is always
-                        * possible, so we just pretend that the upload was
-                        * successful and do the decryption in software.
-                        */
-
-                       /* mark the key as invalid. */
-                       key->hw_key_idx = 0xff;
-                       goto out_unlock;
-               }
-       } else {
-               slot = key->hw_key_idx;
-
-               if (slot == 0xff) {
-                       /* This key was not uploaded into the rx key cache. */
-
-                       goto out_unlock;
-               }
-
-               bitmap_release_region(priv->used_rxkeys, slot, 0);
-               algo = 0;
-       }
-
-       skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*rxkey),
-                           P54_CONTROL_TYPE_RX_KEYCACHE, GFP_KERNEL);
-       if (!skb) {
-               bitmap_release_region(priv->used_rxkeys, slot, 0);
-               ret = -ENOSPC;
-               goto out_unlock;
-       }
-
-       rxkey = (struct p54_keycache *)skb_put(skb, sizeof(*rxkey));
-       rxkey->entry = slot;
-       rxkey->key_id = key->keyidx;
-       rxkey->key_type = algo;
-       if (sta)
-               memcpy(rxkey->mac, sta->addr, ETH_ALEN);
-       else
-               memset(rxkey->mac, ~0, ETH_ALEN);
-       if (key->alg != ALG_TKIP) {
-               rxkey->key_len = min((u8)16, key->keylen);
-               memcpy(rxkey->key, key->key, rxkey->key_len);
-       } else {
-               rxkey->key_len = 24;
-               memcpy(rxkey->key, key->key, 16);
-               memcpy(&(rxkey->key[16]), &(key->key
-                       [NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY]), 8);
-       }
-
-       priv->tx(dev, skb);
-       key->hw_key_idx = slot;
-
-out_unlock:
-       mutex_unlock(&priv->conf_mutex);
-       return ret;
-}
-
-#ifdef CONFIG_P54_LEDS
-static void p54_update_leds(struct work_struct *work)
-{
-       struct p54_common *priv = container_of(work, struct p54_common,
-                                              led_work.work);
-       int err, i, tmp, blink_delay = 400;
-       bool rerun = false;
-
-       /* Don't toggle the LED, when the device is down. */
-       if (priv->mode == NL80211_IFTYPE_UNSPECIFIED)
-               return ;
-
-       for (i = 0; i < ARRAY_SIZE(priv->leds); i++)
-               if (priv->leds[i].toggled) {
-                       priv->softled_state |= BIT(i);
-
-                       tmp = 70 + 200 / (priv->leds[i].toggled);
-                       if (tmp < blink_delay)
-                               blink_delay = tmp;
-
-                       if (priv->leds[i].led_dev.brightness == LED_OFF)
-                               rerun = true;
-
-                       priv->leds[i].toggled =
-                               !!priv->leds[i].led_dev.brightness;
-               } else
-                       priv->softled_state &= ~BIT(i);
-
-       err = p54_set_leds(priv->hw);
-       if (err && net_ratelimit())
-               printk(KERN_ERR "%s: failed to update LEDs.\n",
-                       wiphy_name(priv->hw->wiphy));
-
-       if (rerun)
-               queue_delayed_work(priv->hw->workqueue, &priv->led_work,
-                       msecs_to_jiffies(blink_delay));
-}
-
-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;
-
-       if (priv->mode == NL80211_IFTYPE_UNSPECIFIED)
-               return ;
-
-       if (brightness) {
-               led->toggled++;
-               queue_delayed_work(priv->hw->workqueue, &priv->led_work,
-                                  HZ/10);
-       }
-}
-
-static int p54_register_led(struct ieee80211_hw *dev,
-                           unsigned int led_index,
-                           char *name, char *trigger)
-{
-       struct p54_common *priv = dev->priv;
-       struct p54_led_dev *led = &priv->leds[led_index];
-       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.
-        */
-
-       INIT_DELAYED_WORK(&priv->led_work, p54_update_leds);
-
-       err = p54_register_led(dev, 0, "assoc",
-                              ieee80211_get_assoc_led_name(dev));
-       if (err)
-               return err;
-
-       err = p54_register_led(dev, 1, "tx",
-                              ieee80211_get_tx_led_name(dev));
-       if (err)
-               return err;
-
-       err = p54_register_led(dev, 2, "rx",
-                              ieee80211_get_rx_led_name(dev));
-       if (err)
-               return err;
-
-       err = p54_register_led(dev, 3, "radio",
-                              ieee80211_get_radio_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;
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(priv->leds); i++)
-               if (priv->leds[i].registered)
-                       led_classdev_unregister(&priv->leds[i].led_dev);
-}
-#endif /* CONFIG_P54_LEDS */
-
-static const struct ieee80211_ops p54_ops = {
-       .tx                     = p54_tx,
-       .start                  = p54_start,
-       .stop                   = p54_stop,
-       .add_interface          = p54_add_interface,
-       .remove_interface       = p54_remove_interface,
-       .set_tim                = p54_set_tim,
-       .sta_notify             = p54_sta_notify,
-       .set_key                = p54_set_key,
-       .config                 = p54_config,
-       .bss_info_changed       = p54_bss_info_changed,
-       .configure_filter       = p54_configure_filter,
-       .conf_tx                = p54_conf_tx,
-       .get_stats              = p54_get_stats,
-       .get_tx_stats           = p54_get_tx_stats
-};
-
-struct ieee80211_hw *p54_init_common(size_t priv_data_len)
-{
-       struct ieee80211_hw *dev;
-       struct p54_common *priv;
-
-       dev = ieee80211_alloc_hw(priv_data_len, &p54_ops);
-       if (!dev)
-               return NULL;
-
-       priv = dev->priv;
-       priv->hw = dev;
-       priv->mode = NL80211_IFTYPE_UNSPECIFIED;
-       priv->basic_rate_mask = 0x15f;
-       skb_queue_head_init(&priv->tx_queue);
-       dev->flags = IEEE80211_HW_RX_INCLUDES_FCS |
-                    IEEE80211_HW_SIGNAL_DBM |
-                    IEEE80211_HW_NOISE_DBM;
-
-       dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
-                                     BIT(NL80211_IFTYPE_ADHOC) |
-                                     BIT(NL80211_IFTYPE_AP) |
-                                     BIT(NL80211_IFTYPE_MESH_POINT);
-
-       dev->channel_change_time = 1000;        /* TODO: find actual value */
-       priv->tx_stats[P54_QUEUE_BEACON].limit = 1;
-       priv->tx_stats[P54_QUEUE_FWSCAN].limit = 1;
-       priv->tx_stats[P54_QUEUE_MGMT].limit = 3;
-       priv->tx_stats[P54_QUEUE_CAB].limit = 3;
-       priv->tx_stats[P54_QUEUE_DATA].limit = 5;
-       dev->queues = 1;
-       priv->noise = -94;
-       /*
-        * We support at most 8 tries no matter which rate they're at,
-        * we cannot support max_rates * max_rate_tries as we set it
-        * here, but setting it correctly to 4/2 or so would limit us
-        * artificially if the RC algorithm wants just two rates, so
-        * let's say 4/7, we'll redistribute it at TX time, see the
-        * comments there.
-        */
-       dev->max_rates = 4;
-       dev->max_rate_tries = 7;
-       dev->extra_tx_headroom = sizeof(struct p54_hdr) + 4 +
-                                sizeof(struct p54_tx_data);
-
-       mutex_init(&priv->conf_mutex);
-       init_completion(&priv->eeprom_comp);
-       INIT_DELAYED_WORK(&priv->work, p54_work);
-
-       return dev;
-}
-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_P54_LEDS
-       err = p54_init_leds(dev);
-       if (err)
-               return err;
-#endif /* CONFIG_P54_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);
-       kfree(priv->used_rxkeys);
-
-#ifdef CONFIG_P54_LEDS
-       p54_unregister_leds(dev);
-#endif /* CONFIG_P54_LEDS */
-}
-EXPORT_SYMBOL_GPL(p54_free_common);
diff --git a/drivers/net/wireless/p54/p54common.h b/drivers/net/wireless/p54/p54common.h
deleted file mode 100644 (file)
index 75ead7a..0000000
+++ /dev/null
@@ -1,644 +0,0 @@
-#ifndef P54COMMON_H
-#define P54COMMON_H
-
-/*
- * Common code specific definitions for mac80211 Prism54 drivers
- *
- * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
- * Copyright (c) 2007, Christian Lamparter <chunkeey@web.de>
- *
- * Based on:
- * - the islsm (softmac prism54) driver, which is:
- *   Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
- *
- * - LMAC API interface header file for STLC4560 (lmac_longbow.h)
- *   Copyright (C) 2007 Conexant Systems, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-struct bootrec {
-       __le32 code;
-       __le32 len;
-       u32 data[10];
-} __attribute__((packed));
-
-#define PDR_SYNTH_FRONTEND_MASK                0x0007
-#define PDR_SYNTH_FRONTEND_DUETTE3     0x0001
-#define PDR_SYNTH_FRONTEND_DUETTE2     0x0002
-#define PDR_SYNTH_FRONTEND_FRISBEE     0x0003
-#define PDR_SYNTH_FRONTEND_XBOW                0x0004
-#define PDR_SYNTH_FRONTEND_LONGBOW     0x0005
-#define PDR_SYNTH_IQ_CAL_MASK          0x0018
-#define PDR_SYNTH_IQ_CAL_PA_DETECTOR   0x0000
-#define PDR_SYNTH_IQ_CAL_DISABLED      0x0008
-#define PDR_SYNTH_IQ_CAL_ZIF           0x0010
-#define PDR_SYNTH_FAA_SWITCH_MASK      0x0020
-#define PDR_SYNTH_FAA_SWITCH_ENABLED   0x0020
-#define PDR_SYNTH_24_GHZ_MASK          0x0040
-#define PDR_SYNTH_24_GHZ_DISABLED      0x0040
-#define PDR_SYNTH_5_GHZ_MASK           0x0080
-#define PDR_SYNTH_5_GHZ_DISABLED       0x0080
-#define PDR_SYNTH_RX_DIV_MASK          0x0100
-#define PDR_SYNTH_RX_DIV_SUPPORTED     0x0100
-#define PDR_SYNTH_TX_DIV_MASK          0x0200
-#define PDR_SYNTH_TX_DIV_SUPPORTED     0x0200
-
-struct bootrec_exp_if {
-       __le16 role;
-       __le16 if_id;
-       __le16 variant;
-       __le16 btm_compat;
-       __le16 top_compat;
-} __attribute__((packed));
-
-#define BR_DESC_PRIV_CAP_WEP           BIT(0)
-#define BR_DESC_PRIV_CAP_TKIP          BIT(1)
-#define BR_DESC_PRIV_CAP_MICHAEL       BIT(2)
-#define BR_DESC_PRIV_CAP_CCX_CP                BIT(3)
-#define BR_DESC_PRIV_CAP_CCX_MIC       BIT(4)
-#define BR_DESC_PRIV_CAP_AESCCMP       BIT(5)
-
-struct bootrec_desc {
-       __le16 modes;
-       __le16 flags;
-       __le32 rx_start;
-       __le32 rx_end;
-       u8 headroom;
-       u8 tailroom;
-       u8 tx_queues;
-       u8 tx_depth;
-       u8 privacy_caps;
-       u8 rx_keycache_size;
-       u8 time_size;
-       u8 padding;
-       u8 rates[16];
-       u8 padding2[4];
-       __le16 rx_mtu;
-} __attribute__((packed));
-
-#define BR_CODE_MIN                    0x80000000
-#define BR_CODE_COMPONENT_ID           0x80000001
-#define BR_CODE_COMPONENT_VERSION      0x80000002
-#define BR_CODE_DEPENDENT_IF           0x80000003
-#define BR_CODE_EXPOSED_IF             0x80000004
-#define BR_CODE_DESCR                  0x80000101
-#define BR_CODE_MAX                    0x8FFFFFFF
-#define BR_CODE_END_OF_BRA             0xFF0000FF
-#define LEGACY_BR_CODE_END_OF_BRA      0xFFFFFFFF
-
-#define P54_HDR_FLAG_DATA_ALIGN                BIT(14)
-#define P54_HDR_FLAG_DATA_OUT_PROMISC  BIT(0)
-#define P54_HDR_FLAG_DATA_OUT_TIMESTAMP BIT(1)
-#define P54_HDR_FLAG_DATA_OUT_SEQNR    BIT(2)
-#define P54_HDR_FLAG_DATA_OUT_BIT3     BIT(3)
-#define P54_HDR_FLAG_DATA_OUT_BURST    BIT(4)
-#define P54_HDR_FLAG_DATA_OUT_NOCANCEL BIT(5)
-#define P54_HDR_FLAG_DATA_OUT_CLEARTIM BIT(6)
-#define P54_HDR_FLAG_DATA_OUT_HITCHHIKE        BIT(7)
-#define P54_HDR_FLAG_DATA_OUT_COMPRESS BIT(8)
-#define P54_HDR_FLAG_DATA_OUT_CONCAT   BIT(9)
-#define P54_HDR_FLAG_DATA_OUT_PCS_ACCEPT BIT(10)
-#define P54_HDR_FLAG_DATA_OUT_WAITEOSP BIT(11)
-
-#define P54_HDR_FLAG_DATA_IN_FCS_GOOD  BIT(0)
-#define P54_HDR_FLAG_DATA_IN_MATCH_MAC BIT(1)
-#define P54_HDR_FLAG_DATA_IN_MCBC      BIT(2)
-#define P54_HDR_FLAG_DATA_IN_BEACON    BIT(3)
-#define P54_HDR_FLAG_DATA_IN_MATCH_BSS BIT(4)
-#define P54_HDR_FLAG_DATA_IN_BCAST_BSS BIT(5)
-#define P54_HDR_FLAG_DATA_IN_DATA      BIT(6)
-#define P54_HDR_FLAG_DATA_IN_TRUNCATED BIT(7)
-#define P54_HDR_FLAG_DATA_IN_BIT8      BIT(8)
-#define P54_HDR_FLAG_DATA_IN_TRANSPARENT BIT(9)
-
-/* PDA defines are Copyright (C) 2005 Nokia Corporation (taken from islsm_pda.h) */
-
-struct pda_entry {
-       __le16 len;     /* includes both code and data */
-       __le16 code;
-       u8 data[0];
-} __attribute__ ((packed));
-
-struct eeprom_pda_wrap {
-       __le32 magic;
-       __le16 pad;
-       __le16 len;
-       __le32 arm_opcode;
-       u8 data[0];
-} __attribute__ ((packed));
-
-struct p54_iq_autocal_entry {
-       __le16 iq_param[4];
-} __attribute__ ((packed));
-
-struct pda_iq_autocal_entry {
-        __le16 freq;
-       struct p54_iq_autocal_entry params;
-} __attribute__ ((packed));
-
-struct pda_channel_output_limit {
-       __le16 freq;
-       u8 val_bpsk;
-       u8 val_qpsk;
-       u8 val_16qam;
-       u8 val_64qam;
-       u8 rate_set_mask;
-       u8 rate_set_size;
-} __attribute__ ((packed));
-
-struct pda_pa_curve_data_sample_rev0 {
-       u8 rf_power;
-       u8 pa_detector;
-       u8 pcv;
-} __attribute__ ((packed));
-
-struct pda_pa_curve_data_sample_rev1 {
-       u8 rf_power;
-       u8 pa_detector;
-       u8 data_barker;
-       u8 data_bpsk;
-       u8 data_qpsk;
-       u8 data_16qam;
-       u8 data_64qam;
-} __attribute__ ((packed));
-
-struct p54_pa_curve_data_sample {
-       u8 rf_power;
-       u8 pa_detector;
-       u8 data_barker;
-       u8 data_bpsk;
-       u8 data_qpsk;
-       u8 data_16qam;
-       u8 data_64qam;
-       u8 padding;
-} __attribute__ ((packed));
-
-struct pda_pa_curve_data {
-       u8 cal_method_rev;
-       u8 channels;
-       u8 points_per_channel;
-       u8 padding;
-       u8 data[0];
-} __attribute__ ((packed));
-
-struct pda_rssi_cal_entry {
-       __le16 mul;
-       __le16 add;
-} __attribute__ ((packed));
-
-struct pda_country {
-       u8 regdomain;
-       u8 alpha2[2];
-       u8 flags;
-} __attribute__ ((packed));
-
-/*
- * Warning: Longbow's structures are bogus.
- */
-struct p54_channel_output_limit_longbow {
-       __le16 rf_power_points[12];
-} __attribute__ ((packed));
-
-struct p54_pa_curve_data_sample_longbow {
-       __le16 rf_power;
-       __le16 pa_detector;
-       struct {
-               __le16 data[4];
-       } points[3] __attribute__ ((packed));
-} __attribute__ ((packed));
-
-struct pda_custom_wrapper {
-       __le16 entries;
-       __le16 entry_size;
-       __le16 offset;
-       __le16 len;
-       u8 data[0];
-} __attribute__ ((packed));
-
-/*
- * this defines the PDR codes used to build PDAs as defined in document
- * number 553155. The current implementation mirrors version 1.1 of the
- * document and lists only PDRs supported by the ARM platform.
- */
-
-/* common and choice range (0x0000 - 0x0fff) */
-#define PDR_END                                        0x0000
-#define PDR_MANUFACTURING_PART_NUMBER          0x0001
-#define PDR_PDA_VERSION                                0x0002
-#define PDR_NIC_SERIAL_NUMBER                  0x0003
-
-#define PDR_MAC_ADDRESS                                0x0101
-#define PDR_REGULATORY_DOMAIN_LIST             0x0103
-#define PDR_TEMPERATURE_TYPE                   0x0107
-
-#define PDR_PRISM_PCI_IDENTIFIER               0x0402
-
-/* ARM range (0x1000 - 0x1fff) */
-#define PDR_COUNTRY_INFORMATION                        0x1000
-#define PDR_INTERFACE_LIST                     0x1001
-#define PDR_HARDWARE_PLATFORM_COMPONENT_ID     0x1002
-#define PDR_OEM_NAME                           0x1003
-#define PDR_PRODUCT_NAME                       0x1004
-#define PDR_UTF8_OEM_NAME                      0x1005
-#define PDR_UTF8_PRODUCT_NAME                  0x1006
-#define PDR_COUNTRY_LIST                       0x1007
-#define PDR_DEFAULT_COUNTRY                    0x1008
-
-#define PDR_ANTENNA_GAIN                       0x1100
-
-#define PDR_PRISM_INDIGO_PA_CALIBRATION_DATA   0x1901
-#define PDR_RSSI_LINEAR_APPROXIMATION          0x1902
-#define PDR_PRISM_PA_CAL_OUTPUT_POWER_LIMITS   0x1903
-#define PDR_PRISM_PA_CAL_CURVE_DATA            0x1904
-#define PDR_RSSI_LINEAR_APPROXIMATION_DUAL_BAND        0x1905
-#define PDR_PRISM_ZIF_TX_IQ_CALIBRATION                0x1906
-#define PDR_REGULATORY_POWER_LIMITS            0x1907
-#define PDR_RSSI_LINEAR_APPROXIMATION_EXTENDED 0x1908
-#define PDR_RADIATED_TRANSMISSION_CORRECTION   0x1909
-#define PDR_PRISM_TX_IQ_CALIBRATION            0x190a
-
-/* reserved range (0x2000 - 0x7fff) */
-
-/* customer range (0x8000 - 0xffff) */
-#define PDR_BASEBAND_REGISTERS                         0x8000
-#define PDR_PER_CHANNEL_BASEBAND_REGISTERS             0x8001
-
-/* used by our modificated eeprom image */
-#define PDR_RSSI_LINEAR_APPROXIMATION_CUSTOM           0xDEAD
-#define PDR_PRISM_PA_CAL_OUTPUT_POWER_LIMITS_CUSTOM    0xBEEF
-#define PDR_PRISM_PA_CAL_CURVE_DATA_CUSTOM             0xB05D
-
-/* PDR definitions for default country & country list */
-#define PDR_COUNTRY_CERT_CODE          0x80
-#define PDR_COUNTRY_CERT_CODE_REAL     0x00
-#define PDR_COUNTRY_CERT_CODE_PSEUDO   0x80
-#define PDR_COUNTRY_CERT_BAND          0x40
-#define PDR_COUNTRY_CERT_BAND_2GHZ     0x00
-#define PDR_COUNTRY_CERT_BAND_5GHZ     0x40
-#define PDR_COUNTRY_CERT_IODOOR                0x30
-#define PDR_COUNTRY_CERT_IODOOR_BOTH   0x00
-#define PDR_COUNTRY_CERT_IODOOR_INDOOR 0x20
-#define PDR_COUNTRY_CERT_IODOOR_OUTDOOR        0x30
-#define PDR_COUNTRY_CERT_INDEX         0x0F
-
-struct p54_eeprom_lm86 {
-       union {
-               struct {
-                       __le16 offset;
-                       __le16 len;
-                       u8 data[0];
-               } v1;
-               struct {
-                       __le32 offset;
-                       __le16 len;
-                       u8 magic2;
-                       u8 pad;
-                       u8 magic[4];
-                       u8 data[0];
-               } v2;
-       }  __attribute__ ((packed));
-} __attribute__ ((packed));
-
-enum p54_rx_decrypt_status {
-       P54_DECRYPT_NONE = 0,
-       P54_DECRYPT_OK,
-       P54_DECRYPT_NOKEY,
-       P54_DECRYPT_NOMICHAEL,
-       P54_DECRYPT_NOCKIPMIC,
-       P54_DECRYPT_FAIL_WEP,
-       P54_DECRYPT_FAIL_TKIP,
-       P54_DECRYPT_FAIL_MICHAEL,
-       P54_DECRYPT_FAIL_CKIPKP,
-       P54_DECRYPT_FAIL_CKIPMIC,
-       P54_DECRYPT_FAIL_AESCCMP
-};
-
-struct p54_rx_data {
-       __le16 flags;
-       __le16 len;
-       __le16 freq;
-       u8 antenna;
-       u8 rate;
-       u8 rssi;
-       u8 quality;
-       u8 decrypt_status;
-       u8 rssi_raw;
-       __le32 tsf32;
-       __le32 unalloc0;
-       u8 align[0];
-} __attribute__ ((packed));
-
-enum p54_trap_type {
-       P54_TRAP_SCAN = 0,
-       P54_TRAP_TIMER,
-       P54_TRAP_BEACON_TX,
-       P54_TRAP_FAA_RADIO_ON,
-       P54_TRAP_FAA_RADIO_OFF,
-       P54_TRAP_RADAR,
-       P54_TRAP_NO_BEACON,
-       P54_TRAP_TBTT,
-       P54_TRAP_SCO_ENTER,
-       P54_TRAP_SCO_EXIT
-};
-
-struct p54_trap {
-       __le16 event;
-       __le16 frequency;
-} __attribute__ ((packed));
-
-enum p54_frame_sent_status {
-       P54_TX_OK = 0,
-       P54_TX_FAILED,
-       P54_TX_PSM,
-       P54_TX_PSM_CANCELLED = 4
-};
-
-struct p54_frame_sent {
-       u8 status;
-       u8 tries;
-       u8 ack_rssi;
-       u8 quality;
-       __le16 seq;
-       u8 antenna;
-       u8 padding;
-} __attribute__ ((packed));
-
-enum p54_tx_data_crypt {
-       P54_CRYPTO_NONE = 0,
-       P54_CRYPTO_WEP,
-       P54_CRYPTO_TKIP,
-       P54_CRYPTO_TKIPMICHAEL,
-       P54_CRYPTO_CCX_WEPMIC,
-       P54_CRYPTO_CCX_KPMIC,
-       P54_CRYPTO_CCX_KP,
-       P54_CRYPTO_AESCCMP
-};
-
-enum p54_tx_data_queue {
-       P54_QUEUE_BEACON        = 0,
-       P54_QUEUE_FWSCAN        = 1,
-       P54_QUEUE_MGMT          = 2,
-       P54_QUEUE_CAB           = 3,
-       P54_QUEUE_DATA          = 4,
-
-       P54_QUEUE_AC_NUM        = 4,
-       P54_QUEUE_AC_VO         = 4,
-       P54_QUEUE_AC_VI         = 5,
-       P54_QUEUE_AC_BE         = 6,
-       P54_QUEUE_AC_BK         = 7,
-
-       /* keep last */
-       P54_QUEUE_NUM           = 8,
-};
-
-struct p54_tx_data {
-       u8 rateset[8];
-       u8 rts_rate_idx;
-       u8 crypt_offset;
-       u8 key_type;
-       u8 key_len;
-       u8 key[16];
-       u8 hw_queue;
-       u8 backlog;
-       __le16 durations[4];
-       u8 tx_antenna;
-       union {
-               struct {
-                       u8 cts_rate;
-                       __le16 output_power;
-               } __attribute__((packed)) longbow;
-               struct {
-                       u8 output_power;
-                       u8 cts_rate;
-                       u8 unalloc;
-               } __attribute__ ((packed)) normal;
-       } __attribute__ ((packed));
-       u8 unalloc2[2];
-       u8 align[0];
-} __attribute__ ((packed));
-
-/* unit is ms */
-#define P54_TX_FRAME_LIFETIME 2000
-#define P54_TX_TIMEOUT 4000
-#define P54_STATISTICS_UPDATE 5000
-
-#define P54_FILTER_TYPE_NONE           0
-#define P54_FILTER_TYPE_STATION                BIT(0)
-#define P54_FILTER_TYPE_IBSS           BIT(1)
-#define P54_FILTER_TYPE_AP             BIT(2)
-#define P54_FILTER_TYPE_TRANSPARENT    BIT(3)
-#define P54_FILTER_TYPE_PROMISCUOUS    BIT(4)
-#define P54_FILTER_TYPE_HIBERNATE      BIT(5)
-#define P54_FILTER_TYPE_NOACK          BIT(6)
-#define P54_FILTER_TYPE_RX_DISABLED    BIT(7)
-
-struct p54_setup_mac {
-       __le16 mac_mode;
-       u8 mac_addr[ETH_ALEN];
-       u8 bssid[ETH_ALEN];
-       u8 rx_antenna;
-       u8 rx_align;
-       union {
-               struct {
-                       __le32 basic_rate_mask;
-                       u8 rts_rates[8];
-                       __le32 rx_addr;
-                       __le16 max_rx;
-                       __le16 rxhw;
-                       __le16 wakeup_timer;
-                       __le16 unalloc0;
-               } v1 __attribute__ ((packed));
-               struct {
-                       __le32 rx_addr;
-                       __le16 max_rx;
-                       __le16 rxhw;
-                       __le16 timer;
-                       __le16 truncate;
-                       __le32 basic_rate_mask;
-                       u8 sbss_offset;
-                       u8 mcast_window;
-                       u8 rx_rssi_threshold;
-                       u8 rx_ed_threshold;
-                       __le32 ref_clock;
-                       __le16 lpf_bandwidth;
-                       __le16 osc_start_delay;
-               } v2 __attribute__ ((packed));
-       } __attribute__ ((packed));
-} __attribute__ ((packed));
-
-#define P54_SETUP_V1_LEN 40
-#define P54_SETUP_V2_LEN (sizeof(struct p54_setup_mac))
-
-#define P54_SCAN_EXIT  BIT(0)
-#define P54_SCAN_TRAP  BIT(1)
-#define P54_SCAN_ACTIVE BIT(2)
-#define P54_SCAN_FILTER BIT(3)
-
-struct p54_scan_head {
-       __le16 mode;
-       __le16 dwell;
-       u8 scan_params[20];
-       __le16 freq;
-} __attribute__ ((packed));
-
-struct p54_scan_body {
-       u8 pa_points_per_curve;
-       u8 val_barker;
-       u8 val_bpsk;
-       u8 val_qpsk;
-       u8 val_16qam;
-       u8 val_64qam;
-       struct p54_pa_curve_data_sample curve_data[8];
-       u8 dup_bpsk;
-       u8 dup_qpsk;
-       u8 dup_16qam;
-       u8 dup_64qam;
-} __attribute__ ((packed));
-
-struct p54_scan_body_longbow {
-       struct p54_channel_output_limit_longbow power_limits;
-       struct p54_pa_curve_data_sample_longbow curve_data[8];
-       __le16 unkn[6];         /* maybe more power_limits or rate_mask */
-} __attribute__ ((packed));
-
-union p54_scan_body_union {
-       struct p54_scan_body normal;
-       struct p54_scan_body_longbow longbow;
-} __attribute__ ((packed));
-
-struct p54_scan_tail_rate {
-       __le32 basic_rate_mask;
-       u8 rts_rates[8];
-} __attribute__ ((packed));
-
-struct p54_led {
-       __le16 flags;
-       __le16 mask[2];
-       __le16 delay[2];
-} __attribute__ ((packed));
-
-struct p54_edcf {
-       u8 flags;
-       u8 slottime;
-       u8 sifs;
-       u8 eofpad;
-       struct p54_edcf_queue_param queue[8];
-       u8 mapping[4];
-       __le16 frameburst;
-       __le16 round_trip_delay;
-} __attribute__ ((packed));
-
-struct p54_statistics {
-       __le32 rx_success;
-       __le32 rx_bad_fcs;
-       __le32 rx_abort;
-       __le32 rx_abort_phy;
-       __le32 rts_success;
-       __le32 rts_fail;
-       __le32 tsf32;
-       __le32 airtime;
-       __le32 noise;
-       __le32 sample_noise[8];
-       __le32 sample_cca;
-       __le32 sample_tx;
-} __attribute__ ((packed));
-
-struct p54_xbow_synth {
-       __le16 magic1;
-       __le16 magic2;
-       __le16 freq;
-       u32 padding[5];
-} __attribute__ ((packed));
-
-struct p54_timer {
-       __le32 interval;
-} __attribute__ ((packed));
-
-struct p54_keycache {
-       u8 entry;
-       u8 key_id;
-       u8 mac[ETH_ALEN];
-       u8 padding[2];
-       u8 key_type;
-       u8 key_len;
-       u8 key[24];
-} __attribute__ ((packed));
-
-struct p54_burst {
-       u8 flags;
-       u8 queue;
-       u8 backlog;
-       u8 pad;
-       __le16 durations[32];
-} __attribute__ ((packed));
-
-struct p54_psm_interval {
-       __le16 interval;
-       __le16 periods;
-} __attribute__ ((packed));
-
-#define P54_PSM_CAM                    0
-#define P54_PSM                                BIT(0)
-#define P54_PSM_DTIM                   BIT(1)
-#define P54_PSM_MCBC                   BIT(2)
-#define P54_PSM_CHECKSUM               BIT(3)
-#define P54_PSM_SKIP_MORE_DATA         BIT(4)
-#define P54_PSM_BEACON_TIMEOUT         BIT(5)
-#define P54_PSM_HFOSLEEP               BIT(6)
-#define P54_PSM_AUTOSWITCH_SLEEP       BIT(7)
-#define P54_PSM_LPIT                   BIT(8)
-#define P54_PSM_BF_UCAST_SKIP          BIT(9)
-#define P54_PSM_BF_MCAST_SKIP          BIT(10)
-
-struct p54_psm {
-       __le16 mode;
-       __le16 aid;
-       struct p54_psm_interval intervals[4];
-       u8 beacon_rssi_skip_max;
-       u8 rssi_delta_threshold;
-       u8 nr;
-       u8 exclude[1];
-} __attribute__ ((packed));
-
-#define MC_FILTER_ADDRESS_NUM 4
-
-struct p54_group_address_table {
-       __le16 filter_enable;
-       __le16 num_address;
-       u8 mac_list[MC_FILTER_ADDRESS_NUM][ETH_ALEN];
-} __attribute__ ((packed));
-
-struct p54_txcancel {
-       __le32 req_id;
-} __attribute__ ((packed));
-
-struct p54_sta_unlock {
-       u8 addr[ETH_ALEN];
-       u16 padding;
-} __attribute__ ((packed));
-
-#define P54_TIM_CLEAR BIT(15)
-struct p54_tim {
-       u8 count;
-       u8 padding[3];
-       __le16 entry[8];
-} __attribute__ ((packed));
-
-struct p54_cce_quiet {
-       __le32 period;
-} __attribute__ ((packed));
-
-struct p54_bt_balancer {
-       __le16 prio_thresh;
-       __le16 acl_thresh;
-} __attribute__ ((packed));
-
-struct p54_arp_table {
-       __le16 filter_enable;
-       u8 ipv4_addr[4];
-} __attribute__ ((packed));
-
-#endif /* P54COMMON_H */
index b1610ea..d348c26 100644 (file)
@@ -22,6 +22,7 @@
 #include <net/mac80211.h>
 
 #include "p54.h"
+#include "lmac.h"
 #include "p54pci.h"
 
 MODULE_AUTHOR("Michael Wu <flamingice@sourmilk.net>");
@@ -564,7 +565,6 @@ static int __devinit p54p_probe(struct pci_dev *pdev,
 
  err_free_common:
        release_firmware(priv->firmware);
-       p54_free_common(dev);
        pci_free_consistent(pdev, sizeof(*priv->ring_control),
                            priv->ring_control, priv->ring_control_dma);
 
@@ -573,7 +573,7 @@ static int __devinit p54p_probe(struct pci_dev *pdev,
 
  err_free_dev:
        pci_set_drvdata(pdev, NULL);
-       ieee80211_free_hw(dev);
+       p54_free_common(dev);
 
  err_free_reg:
        pci_release_regions(pdev);
@@ -590,16 +590,15 @@ static void __devexit p54p_remove(struct pci_dev *pdev)
        if (!dev)
                return;
 
-       ieee80211_unregister_hw(dev);
+       p54_unregister_common(dev);
        priv = dev->priv;
        release_firmware(priv->firmware);
        pci_free_consistent(pdev, sizeof(*priv->ring_control),
                            priv->ring_control, priv->ring_control_dma);
-       p54_free_common(dev);
        iounmap(priv->map);
        pci_release_regions(pdev);
        pci_disable_device(pdev);
-       ieee80211_free_hw(dev);
+       p54_free_common(dev);
 }
 
 #ifdef CONFIG_PM
index 72c7dbd..eef5329 100644 (file)
@@ -34,7 +34,7 @@
 #include "p54spi_eeprom.h"
 #include "p54.h"
 
-#include "p54common.h"
+#include "lmac.h"
 
 MODULE_FIRMWARE("3826.arm");
 MODULE_ALIAS("stlc45xx");
@@ -111,15 +111,6 @@ static void p54spi_spi_write(struct p54s_priv *priv, u8 address,
        spi_sync(priv->spi, &m);
 }
 
-static u16 p54spi_read16(struct p54s_priv *priv, u8 addr)
-{
-       __le16 val;
-
-       p54spi_spi_read(priv, addr, &val, sizeof(val));
-
-       return le16_to_cpu(val);
-}
-
 static u32 p54spi_read32(struct p54s_priv *priv, u8 addr)
 {
        __le32 val;
@@ -139,37 +130,12 @@ static inline void p54spi_write32(struct p54s_priv *priv, u8 addr, __le32 val)
        p54spi_spi_write(priv, addr, &val, sizeof(val));
 }
 
-struct p54spi_spi_reg {
-       u16 address;            /* __le16 ? */
-       u16 length;
-       char *name;
-};
-
-static const struct p54spi_spi_reg p54spi_registers_array[] =
-{
-       { SPI_ADRS_ARM_INTERRUPTS,      32, "ARM_INT     " },
-       { SPI_ADRS_ARM_INT_EN,          32, "ARM_INT_ENA " },
-       { SPI_ADRS_HOST_INTERRUPTS,     32, "HOST_INT    " },
-       { SPI_ADRS_HOST_INT_EN,         32, "HOST_INT_ENA" },
-       { SPI_ADRS_HOST_INT_ACK,        32, "HOST_INT_ACK" },
-       { SPI_ADRS_GEN_PURP_1,          32, "GP1_COMM    " },
-       { SPI_ADRS_GEN_PURP_2,          32, "GP2_COMM    " },
-       { SPI_ADRS_DEV_CTRL_STAT,       32, "DEV_CTRL_STA" },
-       { SPI_ADRS_DMA_DATA,            16, "DMA_DATA    " },
-       { SPI_ADRS_DMA_WRITE_CTRL,      16, "DMA_WR_CTRL " },
-       { SPI_ADRS_DMA_WRITE_LEN,       16, "DMA_WR_LEN  " },
-       { SPI_ADRS_DMA_WRITE_BASE,      32, "DMA_WR_BASE " },
-       { SPI_ADRS_DMA_READ_CTRL,       16, "DMA_RD_CTRL " },
-       { SPI_ADRS_DMA_READ_LEN,        16, "DMA_RD_LEN  " },
-       { SPI_ADRS_DMA_WRITE_BASE,      32, "DMA_RD_BASE " }
-};
-
-static int p54spi_wait_bit(struct p54s_priv *priv, u16 reg, __le32 bits)
+static int p54spi_wait_bit(struct p54s_priv *priv, u16 reg, u32 bits)
 {
        int i;
 
        for (i = 0; i < 2000; i++) {
-               __le32 buffer = p54spi_read32(priv, reg);
+               u32 buffer = p54spi_read32(priv, reg);
                if ((buffer & bits) == bits)
                        return 1;
        }
@@ -179,8 +145,7 @@ static int p54spi_wait_bit(struct p54s_priv *priv, u16 reg, __le32 bits)
 static int p54spi_spi_write_dma(struct p54s_priv *priv, __le32 base,
                                const void *buf, size_t len)
 {
-       if (!p54spi_wait_bit(priv, SPI_ADRS_DMA_WRITE_CTRL,
-                            cpu_to_le32(HOST_ALLOWED))) {
+       if (!p54spi_wait_bit(priv, SPI_ADRS_DMA_WRITE_CTRL, HOST_ALLOWED)) {
                dev_err(&priv->spi->dev, "spi_write_dma not allowed "
                        "to DMA write.\n");
                return -EAGAIN;
@@ -333,7 +298,7 @@ static int p54spi_wakeup(struct p54s_priv *priv)
 
        /* And wait for the READY interrupt */
        if (!p54spi_wait_bit(priv, SPI_ADRS_HOST_INTERRUPTS,
-                            cpu_to_le32(SPI_HOST_INT_READY))) {
+                            SPI_HOST_INT_READY)) {
                dev_err(&priv->spi->dev, "INT_READY timeout\n");
                return -EBUSY;
        }
@@ -444,7 +409,7 @@ static int p54spi_tx_frame(struct p54s_priv *priv, struct sk_buff *skb)
                goto out;
 
        if (!p54spi_wait_bit(priv, SPI_ADRS_HOST_INTERRUPTS,
-                            cpu_to_le32(SPI_HOST_INT_WR_READY))) {
+                            SPI_HOST_INT_WR_READY)) {
                dev_err(&priv->spi->dev, "WR_READY timeout\n");
                ret = -EAGAIN;
                goto out;
@@ -713,7 +678,7 @@ static int __devexit p54spi_remove(struct spi_device *spi)
 {
        struct p54s_priv *priv = dev_get_drvdata(&spi->dev);
 
-       ieee80211_unregister_hw(priv->hw);
+       p54_unregister_common(priv->hw);
 
        free_irq(gpio_to_irq(p54spi_gpio_irq), spi);
 
@@ -724,7 +689,6 @@ static int __devexit p54spi_remove(struct spi_device *spi)
        mutex_destroy(&priv->mutex);
 
        p54_free_common(priv->hw);
-       ieee80211_free_hw(priv->hw);
 
        return 0;
 }
index 0e877a1..e44460f 100644 (file)
@@ -22,6 +22,7 @@
 #include <net/mac80211.h>
 
 #include "p54.h"
+#include "lmac.h"
 #include "p54usb.h"
 
 MODULE_AUTHOR("Michael Wu <flamingice@sourmilk.net>");
@@ -245,8 +246,10 @@ static void p54u_tx_lm87(struct ieee80211_hw *dev, struct sk_buff *skb)
        struct lm87_tx_hdr *hdr = (void *)skb->data - sizeof(*hdr);
 
        data_urb = usb_alloc_urb(0, GFP_ATOMIC);
-       if (!data_urb)
+       if (!data_urb) {
+               p54_free_skb(dev, skb);
                return;
+       }
 
        hdr->chksum = p54u_lm87_chksum((__le32 *)skb->data, skb->len);
        hdr->device_addr = ((struct p54_hdr *)skb->data)->req_id;
@@ -268,27 +271,22 @@ static void p54u_tx_lm87(struct ieee80211_hw *dev, struct sk_buff *skb)
 static void p54u_tx_net2280(struct ieee80211_hw *dev, struct sk_buff *skb)
 {
        struct p54u_priv *priv = dev->priv;
-       struct urb *int_urb, *data_urb;
+       struct urb *int_urb = NULL, *data_urb = NULL;
        struct net2280_tx_hdr *hdr = (void *)skb->data - sizeof(*hdr);
-       struct net2280_reg_write *reg;
-       int err = 0;
+       struct net2280_reg_write *reg = NULL;
+       int err = -ENOMEM;
 
        reg = kmalloc(sizeof(*reg), GFP_ATOMIC);
        if (!reg)
-               return;
+               goto out;
 
        int_urb = usb_alloc_urb(0, GFP_ATOMIC);
-       if (!int_urb) {
-               kfree(reg);
-               return;
-       }
+       if (!int_urb)
+               goto out;
 
        data_urb = usb_alloc_urb(0, GFP_ATOMIC);
-       if (!data_urb) {
-               kfree(reg);
-               usb_free_urb(int_urb);
-               return;
-       }
+       if (!data_urb)
+               goto out;
 
        reg->port = cpu_to_le16(NET2280_DEV_U32);
        reg->addr = cpu_to_le32(P54U_DEV_BASE);
@@ -303,11 +301,12 @@ static void p54u_tx_net2280(struct ieee80211_hw *dev, struct sk_buff *skb)
                p54u_tx_dummy_cb, dev);
 
        /*
-        * This flag triggers a code path in the USB subsystem that will
-        * free what's inside the transfer_buffer after the callback routine
-        * has completed.
+        * URB_FREE_BUFFER triggers a code path in the USB subsystem that will
+        * free what is inside the transfer_buffer after the last reference to
+        * the int_urb is dropped.
         */
        int_urb->transfer_flags |= URB_FREE_BUFFER | URB_ZERO_PACKET;
+       reg = NULL;
 
        usb_fill_bulk_urb(data_urb, priv->udev,
                          usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA),
@@ -328,12 +327,12 @@ static void p54u_tx_net2280(struct ieee80211_hw *dev, struct sk_buff *skb)
                usb_unanchor_urb(data_urb);
                goto out;
        }
- out:
+out:
        usb_free_urb(int_urb);
        usb_free_urb(data_urb);
 
        if (err) {
-               skb_pull(skb, sizeof(*hdr));
+               kfree(reg);
                p54_free_skb(dev, skb);
        }
 }
@@ -961,7 +960,7 @@ err_free_fw:
        release_firmware(priv->fw);
 
 err_free_dev:
-       ieee80211_free_hw(dev);
+       p54_free_common(dev);
        usb_set_intfdata(intf, NULL);
        usb_put_dev(udev);
        return err;
@@ -975,13 +974,12 @@ static void __devexit p54u_disconnect(struct usb_interface *intf)
        if (!dev)
                return;
 
-       ieee80211_unregister_hw(dev);
+       p54_unregister_common(dev);
 
        priv = dev->priv;
        usb_put_dev(interface_to_usbdev(intf));
        release_firmware(priv->fw);
        p54_free_common(dev);
-       ieee80211_free_hw(dev);
 }
 
 static int p54u_pre_reset(struct usb_interface *intf)
diff --git a/drivers/net/wireless/p54/txrx.c b/drivers/net/wireless/p54/txrx.c
new file mode 100644 (file)
index 0000000..6426d2c
--- /dev/null
@@ -0,0 +1,826 @@
+/*
+ * Common code for mac80211 Prism54 drivers
+ *
+ * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
+ * Copyright (c) 2007-2009, Christian Lamparter <chunkeey@web.de>
+ * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
+ *
+ * Based on:
+ * - the islsm (softmac prism54) driver, which is:
+ *   Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
+ * - stlc45xx driver
+ *   Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/firmware.h>
+#include <linux/etherdevice.h>
+
+#include <net/mac80211.h>
+
+#include "p54.h"
+#include "lmac.h"
+
+#ifdef P54_MM_DEBUG
+static void p54_dump_tx_queue(struct p54_common *priv)
+{
+       unsigned long flags;
+       struct ieee80211_tx_info *info;
+       struct p54_tx_info *range;
+       struct sk_buff *skb;
+       struct p54_hdr *hdr;
+       unsigned int i = 0;
+       u32 prev_addr;
+       u32 largest_hole = 0, free;
+
+       spin_lock_irqsave(&priv->tx_queue.lock, flags);
+       printk(KERN_DEBUG "%s: / --- tx queue dump (%d entries) --- \n",
+              wiphy_name(priv->hw->wiphy), skb_queue_len(&priv->tx_queue));
+
+       prev_addr = priv->rx_start;
+       skb_queue_walk(&priv->tx_queue, skb) {
+               info = IEEE80211_SKB_CB(skb);
+               range = (void *) info->rate_driver_data;
+               hdr = (void *) skb->data;
+
+               free = range->start_addr - prev_addr;
+               printk(KERN_DEBUG "%s: | [%02d] => [skb:%p skb_len:0x%04x "
+                      "hdr:{flags:%02x len:%04x req_id:%04x type:%02x} "
+                      "mem:{start:%04x end:%04x, free:%d}]\n",
+                      wiphy_name(priv->hw->wiphy), i++, skb, skb->len,
+                      le16_to_cpu(hdr->flags), le16_to_cpu(hdr->len),
+                      le32_to_cpu(hdr->req_id), le16_to_cpu(hdr->type),
+                      range->start_addr, range->end_addr, free);
+
+               prev_addr = range->end_addr;
+               largest_hole = max(largest_hole, free);
+       }
+       free = priv->rx_end - prev_addr;
+       largest_hole = max(largest_hole, free);
+       printk(KERN_DEBUG "%s: \\ --- [free: %d], largest free block: %d ---\n",
+              wiphy_name(priv->hw->wiphy), free, largest_hole);
+       spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
+}
+#endif /* P54_MM_DEBUG */
+
+/*
+ * So, the firmware is somewhat stupid and doesn't know what places in its
+ * memory incoming data should go to. By poking around in the firmware, we
+ * can find some unused memory to upload our packets to. However, data that we
+ * want the card to TX needs to stay intact until the card has told us that
+ * it is done with it. This function finds empty places we can upload to and
+ * marks allocated areas as reserved if necessary. p54_find_and_unlink_skb or
+ * p54_free_skb frees allocated areas.
+ */
+static int p54_assign_address(struct p54_common *priv, struct sk_buff *skb)
+{
+       struct sk_buff *entry, *target_skb = NULL;
+       struct ieee80211_tx_info *info;
+       struct p54_tx_info *range;
+       struct p54_hdr *data = (void *) skb->data;
+       unsigned long flags;
+       u32 last_addr = priv->rx_start;
+       u32 target_addr = priv->rx_start;
+       u16 len = priv->headroom + skb->len + priv->tailroom + 3;
+
+       if (unlikely(WARN_ON(!skb || !priv)))
+               return -EINVAL;
+
+       info = IEEE80211_SKB_CB(skb);
+       range = (void *) info->rate_driver_data;
+       len = (range->extra_len + len) & ~0x3;
+
+       spin_lock_irqsave(&priv->tx_queue.lock, flags);
+       if (unlikely(skb_queue_len(&priv->tx_queue) == 32)) {
+               /*
+                * The tx_queue is now really full.
+                *
+                * TODO: check if the device has crashed and reset it.
+                */
+               spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
+               return -EBUSY;
+       }
+
+       skb_queue_walk(&priv->tx_queue, entry) {
+               u32 hole_size;
+               info = IEEE80211_SKB_CB(entry);
+               range = (void *) info->rate_driver_data;
+               hole_size = range->start_addr - last_addr;
+
+               if (!entry->next) {
+                       spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
+                       return -ENOSPC;
+               }
+
+               if (!target_skb && hole_size >= len) {
+                       target_skb = entry->prev;
+                       hole_size -= len;
+                       target_addr = last_addr;
+                       break;
+               }
+               last_addr = range->end_addr;
+       }
+       if (unlikely(!target_skb)) {
+               if (priv->rx_end - last_addr >= len) {
+                       target_skb = priv->tx_queue.prev;
+                       if (!skb_queue_empty(&priv->tx_queue)) {
+                               info = IEEE80211_SKB_CB(target_skb);
+                               range = (void *)info->rate_driver_data;
+                               target_addr = range->end_addr;
+                       }
+               } else {
+                       spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
+                       return -ENOSPC;
+               }
+       }
+
+       info = IEEE80211_SKB_CB(skb);
+       range = (void *) info->rate_driver_data;
+       range->start_addr = target_addr;
+       range->end_addr = target_addr + len;
+       __skb_queue_after(&priv->tx_queue, target_skb, skb);
+       spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
+       data->req_id = cpu_to_le32(target_addr + priv->headroom);
+       return 0;
+}
+
+static void p54_tx_pending(struct p54_common *priv)
+{
+       struct sk_buff *skb;
+       int ret;
+
+       if (unlikely(WARN_ON(!priv)))
+               return ;
+
+       skb = skb_dequeue(&priv->tx_pending);
+       if (unlikely(!skb))
+               return ;
+
+       ret = p54_assign_address(priv, skb);
+       if (unlikely(ret))
+               skb_queue_head(&priv->tx_pending, skb);
+       else
+               priv->tx(priv->hw, skb);
+}
+
+static void p54_wake_queues(struct p54_common *priv)
+{
+       unsigned long flags;
+       unsigned int i;
+
+       if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED))
+               return ;
+
+       p54_tx_pending(priv);
+
+       spin_lock_irqsave(&priv->tx_stats_lock, flags);
+       for (i = 0; i < priv->hw->queues; i++) {
+               if (priv->tx_stats[i + P54_QUEUE_DATA].len <
+                   priv->tx_stats[i + P54_QUEUE_DATA].limit)
+                       ieee80211_wake_queue(priv->hw, i);
+       }
+       spin_unlock_irqrestore(&priv->tx_stats_lock, flags);
+}
+
+static int p54_tx_qos_accounting_alloc(struct p54_common *priv,
+                                      struct sk_buff *skb,
+                                      const u16 p54_queue)
+{
+       struct ieee80211_tx_queue_stats *queue;
+       unsigned long flags;
+
+       if (WARN_ON(p54_queue > P54_QUEUE_NUM))
+               return -EINVAL;
+
+       queue = &priv->tx_stats[p54_queue];
+
+       spin_lock_irqsave(&priv->tx_stats_lock, flags);
+       if (unlikely(queue->len >= queue->limit && IS_QOS_QUEUE(p54_queue))) {
+               spin_unlock_irqrestore(&priv->tx_stats_lock, flags);
+               return -ENOSPC;
+       }
+
+       queue->len++;
+       queue->count++;
+
+       if (unlikely(queue->len == queue->limit && IS_QOS_QUEUE(p54_queue))) {
+               u16 ac_queue = p54_queue - P54_QUEUE_DATA;
+               ieee80211_stop_queue(priv->hw, ac_queue);
+       }
+
+       spin_unlock_irqrestore(&priv->tx_stats_lock, flags);
+       return 0;
+}
+
+static void p54_tx_qos_accounting_free(struct p54_common *priv,
+                                      struct sk_buff *skb)
+{
+       if (skb && IS_DATA_FRAME(skb)) {
+               struct p54_hdr *hdr = (void *) skb->data;
+               struct p54_tx_data *data = (void *) hdr->data;
+               unsigned long flags;
+
+               spin_lock_irqsave(&priv->tx_stats_lock, flags);
+               priv->tx_stats[data->hw_queue].len--;
+               spin_unlock_irqrestore(&priv->tx_stats_lock, flags);
+       }
+       p54_wake_queues(priv);
+}
+
+void p54_free_skb(struct ieee80211_hw *dev, struct sk_buff *skb)
+{
+       struct p54_common *priv = dev->priv;
+       if (unlikely(!skb))
+               return ;
+
+       skb_unlink(skb, &priv->tx_queue);
+       p54_tx_qos_accounting_free(priv, skb);
+       dev_kfree_skb_any(skb);
+}
+EXPORT_SYMBOL_GPL(p54_free_skb);
+
+static struct sk_buff *p54_find_and_unlink_skb(struct p54_common *priv,
+                                              const __le32 req_id)
+{
+       struct sk_buff *entry;
+       unsigned long flags;
+
+       spin_lock_irqsave(&priv->tx_queue.lock, flags);
+       skb_queue_walk(&priv->tx_queue, entry) {
+               struct p54_hdr *hdr = (struct p54_hdr *) entry->data;
+
+               if (hdr->req_id == req_id) {
+                       __skb_unlink(entry, &priv->tx_queue);
+                       spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
+                       p54_tx_qos_accounting_free(priv, entry);
+                       return entry;
+               }
+       }
+       spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
+       return NULL;
+}
+
+void p54_tx(struct p54_common *priv, struct sk_buff *skb)
+{
+       if (unlikely(WARN_ON(!priv)))
+               return ;
+
+       skb_queue_tail(&priv->tx_pending, skb);
+       p54_tx_pending(priv);
+}
+
+static int p54_rssi_to_dbm(struct p54_common *priv, int rssi)
+{
+       int band = priv->hw->conf.channel->band;
+
+       if (priv->rxhw != 5)
+               return ((rssi * priv->rssical_db[band].mul) / 64 +
+                        priv->rssical_db[band].add) / 4;
+       else
+               /*
+                * TODO: find the correct formula
+                */
+               return ((rssi * priv->rssical_db[band].mul) / 64 +
+                        priv->rssical_db[band].add) / 4;
+}
+
+static int p54_rx_data(struct p54_common *priv, struct sk_buff *skb)
+{
+       struct p54_rx_data *hdr = (struct p54_rx_data *) skb->data;
+       struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb);
+       u16 freq = le16_to_cpu(hdr->freq);
+       size_t header_len = sizeof(*hdr);
+       u32 tsf32;
+       u8 rate = hdr->rate & 0xf;
+
+       /*
+        * If the device is in a unspecified state we have to
+        * ignore all data frames. Else we could end up with a
+        * nasty crash.
+        */
+       if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED))
+               return 0;
+
+       if (!(hdr->flags & cpu_to_le16(P54_HDR_FLAG_DATA_IN_FCS_GOOD)))
+               return 0;
+
+       if (hdr->decrypt_status == P54_DECRYPT_OK)
+               rx_status->flag |= RX_FLAG_DECRYPTED;
+       if ((hdr->decrypt_status == P54_DECRYPT_FAIL_MICHAEL) ||
+           (hdr->decrypt_status == P54_DECRYPT_FAIL_TKIP))
+               rx_status->flag |= RX_FLAG_MMIC_ERROR;
+
+       rx_status->signal = p54_rssi_to_dbm(priv, hdr->rssi);
+       rx_status->noise = priv->noise;
+       if (hdr->rate & 0x10)
+               rx_status->flag |= RX_FLAG_SHORTPRE;
+       if (priv->hw->conf.channel->band == IEEE80211_BAND_5GHZ)
+               rx_status->rate_idx = (rate < 4) ? 0 : rate - 4;
+       else
+               rx_status->rate_idx = rate;
+
+       rx_status->freq = freq;
+       rx_status->band =  priv->hw->conf.channel->band;
+       rx_status->antenna = hdr->antenna;
+
+       tsf32 = le32_to_cpu(hdr->tsf32);
+       if (tsf32 < priv->tsf_low32)
+               priv->tsf_high32++;
+       rx_status->mactime = ((u64)priv->tsf_high32) << 32 | tsf32;
+       priv->tsf_low32 = tsf32;
+
+       rx_status->flag |= RX_FLAG_TSFT;
+
+       if (hdr->flags & cpu_to_le16(P54_HDR_FLAG_DATA_ALIGN))
+               header_len += hdr->align[0];
+
+       skb_pull(skb, header_len);
+       skb_trim(skb, le16_to_cpu(hdr->len));
+       ieee80211_rx_irqsafe(priv->hw, skb);
+
+       queue_delayed_work(priv->hw->workqueue, &priv->work,
+                          msecs_to_jiffies(P54_STATISTICS_UPDATE));
+
+       return -1;
+}
+
+static void p54_rx_frame_sent(struct p54_common *priv, struct sk_buff *skb)
+{
+       struct p54_hdr *hdr = (struct p54_hdr *) skb->data;
+       struct p54_frame_sent *payload = (struct p54_frame_sent *) hdr->data;
+       struct ieee80211_tx_info *info;
+       struct p54_hdr *entry_hdr;
+       struct p54_tx_data *entry_data;
+       struct sk_buff *entry;
+       unsigned int pad = 0, frame_len;
+       int count, idx;
+
+       entry = p54_find_and_unlink_skb(priv, hdr->req_id);
+       if (unlikely(!entry))
+               return ;
+
+       frame_len = entry->len;
+       info = IEEE80211_SKB_CB(entry);
+       entry_hdr = (struct p54_hdr *) entry->data;
+       entry_data = (struct p54_tx_data *) entry_hdr->data;
+       priv->stats.dot11ACKFailureCount += payload->tries - 1;
+
+       /*
+        * Frames in P54_QUEUE_FWSCAN and P54_QUEUE_BEACON are
+        * generated by the driver. Therefore tx_status is bogus
+        * and we don't want to confuse the mac80211 stack.
+        */
+       if (unlikely(entry_data->hw_queue < P54_QUEUE_FWSCAN)) {
+               if (entry_data->hw_queue == P54_QUEUE_BEACON &&
+                   hdr->req_id == priv->beacon_req_id)
+                       priv->beacon_req_id = cpu_to_le32(0);
+
+               dev_kfree_skb_any(entry);
+               return ;
+       }
+
+       /*
+        * Clear manually, ieee80211_tx_info_clear_status would
+        * clear the counts too and we need them.
+        */
+       memset(&info->status.ampdu_ack_len, 0,
+              sizeof(struct ieee80211_tx_info) -
+              offsetof(struct ieee80211_tx_info, status.ampdu_ack_len));
+       BUILD_BUG_ON(offsetof(struct ieee80211_tx_info,
+                             status.ampdu_ack_len) != 23);
+
+       if (entry_hdr->flags & cpu_to_le16(P54_HDR_FLAG_DATA_ALIGN))
+               pad = entry_data->align[0];
+
+       /* walk through the rates array and adjust the counts */
+       count = payload->tries;
+       for (idx = 0; idx < 4; idx++) {
+               if (count >= info->status.rates[idx].count) {
+                       count -= info->status.rates[idx].count;
+               } else if (count > 0) {
+                       info->status.rates[idx].count = count;
+                       count = 0;
+               } else {
+                       info->status.rates[idx].idx = -1;
+                       info->status.rates[idx].count = 0;
+               }
+       }
+
+       if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) &&
+            (!payload->status))
+               info->flags |= IEEE80211_TX_STAT_ACK;
+       if (payload->status & P54_TX_PSM_CANCELLED)
+               info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
+       info->status.ack_signal = p54_rssi_to_dbm(priv,
+                                                 (int)payload->ack_rssi);
+
+       /* Undo all changes to the frame. */
+       switch (entry_data->key_type) {
+       case P54_CRYPTO_TKIPMICHAEL: {
+               u8 *iv = (u8 *)(entry_data->align + pad +
+                               entry_data->crypt_offset);
+
+               /* Restore the original TKIP IV. */
+               iv[2] = iv[0];
+               iv[0] = iv[1];
+               iv[1] = (iv[0] | 0x20) & 0x7f;  /* WEPSeed - 8.3.2.2 */
+
+               frame_len -= 12; /* remove TKIP_MMIC + TKIP_ICV */
+               break;
+               }
+       case P54_CRYPTO_AESCCMP:
+               frame_len -= 8; /* remove CCMP_MIC */
+               break;
+       case P54_CRYPTO_WEP:
+               frame_len -= 4; /* remove WEP_ICV */
+               break;
+       }
+
+       skb_trim(entry, frame_len);
+       skb_pull(entry, sizeof(*hdr) + pad + sizeof(*entry_data));
+       ieee80211_tx_status_irqsafe(priv->hw, entry);
+}
+
+static void p54_rx_eeprom_readback(struct p54_common *priv,
+                                  struct sk_buff *skb)
+{
+       struct p54_hdr *hdr = (struct p54_hdr *) skb->data;
+       struct p54_eeprom_lm86 *eeprom = (struct p54_eeprom_lm86 *) hdr->data;
+       struct sk_buff *tmp;
+
+       if (!priv->eeprom)
+               return ;
+
+       if (priv->fw_var >= 0x509) {
+               memcpy(priv->eeprom, eeprom->v2.data,
+                      le16_to_cpu(eeprom->v2.len));
+       } else {
+               memcpy(priv->eeprom, eeprom->v1.data,
+                      le16_to_cpu(eeprom->v1.len));
+       }
+
+       priv->eeprom = NULL;
+       tmp = p54_find_and_unlink_skb(priv, hdr->req_id);
+       dev_kfree_skb_any(tmp);
+       complete(&priv->eeprom_comp);
+}
+
+static void p54_rx_stats(struct p54_common *priv, struct sk_buff *skb)
+{
+       struct p54_hdr *hdr = (struct p54_hdr *) skb->data;
+       struct p54_statistics *stats = (struct p54_statistics *) hdr->data;
+       struct sk_buff *tmp;
+       u32 tsf32;
+
+       if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED))
+               return ;
+
+       tsf32 = le32_to_cpu(stats->tsf32);
+       if (tsf32 < priv->tsf_low32)
+               priv->tsf_high32++;
+       priv->tsf_low32 = tsf32;
+
+       priv->stats.dot11RTSFailureCount = le32_to_cpu(stats->rts_fail);
+       priv->stats.dot11RTSSuccessCount = le32_to_cpu(stats->rts_success);
+       priv->stats.dot11FCSErrorCount = le32_to_cpu(stats->rx_bad_fcs);
+
+       priv->noise = p54_rssi_to_dbm(priv, le32_to_cpu(stats->noise));
+
+       tmp = p54_find_and_unlink_skb(priv, hdr->req_id);
+       dev_kfree_skb_any(tmp);
+}
+
+static void p54_rx_trap(struct p54_common *priv, struct sk_buff *skb)
+{
+       struct p54_hdr *hdr = (struct p54_hdr *) skb->data;
+       struct p54_trap *trap = (struct p54_trap *) hdr->data;
+       u16 event = le16_to_cpu(trap->event);
+       u16 freq = le16_to_cpu(trap->frequency);
+
+       switch (event) {
+       case P54_TRAP_BEACON_TX:
+               break;
+       case P54_TRAP_RADAR:
+               printk(KERN_INFO "%s: radar (freq:%d MHz)\n",
+                       wiphy_name(priv->hw->wiphy), freq);
+               break;
+       case P54_TRAP_NO_BEACON:
+               if (priv->vif)
+                       ieee80211_beacon_loss(priv->vif);
+               break;
+       case P54_TRAP_SCAN:
+               break;
+       case P54_TRAP_TBTT:
+               break;
+       case P54_TRAP_TIMER:
+               break;
+       default:
+               printk(KERN_INFO "%s: received event:%x freq:%d\n",
+                      wiphy_name(priv->hw->wiphy), event, freq);
+               break;
+       }
+}
+
+static int p54_rx_control(struct p54_common *priv, struct sk_buff *skb)
+{
+       struct p54_hdr *hdr = (struct p54_hdr *) skb->data;
+
+       switch (le16_to_cpu(hdr->type)) {
+       case P54_CONTROL_TYPE_TXDONE:
+               p54_rx_frame_sent(priv, skb);
+               break;
+       case P54_CONTROL_TYPE_TRAP:
+               p54_rx_trap(priv, skb);
+               break;
+       case P54_CONTROL_TYPE_BBP:
+               break;
+       case P54_CONTROL_TYPE_STAT_READBACK:
+               p54_rx_stats(priv, skb);
+               break;
+       case P54_CONTROL_TYPE_EEPROM_READBACK:
+               p54_rx_eeprom_readback(priv, skb);
+               break;
+       default:
+               printk(KERN_DEBUG "%s: not handling 0x%02x type control frame\n",
+                      wiphy_name(priv->hw->wiphy), le16_to_cpu(hdr->type));
+               break;
+       }
+       return 0;
+}
+
+/* returns zero if skb can be reused */
+int p54_rx(struct ieee80211_hw *dev, struct sk_buff *skb)
+{
+       struct p54_common *priv = dev->priv;
+       u16 type = le16_to_cpu(*((__le16 *)skb->data));
+
+       if (type & P54_HDR_FLAG_CONTROL)
+               return p54_rx_control(priv, skb);
+       else
+               return p54_rx_data(priv, skb);
+}
+EXPORT_SYMBOL_GPL(p54_rx);
+
+static void p54_tx_80211_header(struct p54_common *priv, struct sk_buff *skb,
+                               struct ieee80211_tx_info *info, u8 *queue,
+                               u32 *extra_len, u16 *flags, u16 *aid,
+                               bool *burst_possible)
+{
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+
+       if (ieee80211_is_data_qos(hdr->frame_control))
+               *burst_possible = true;
+       else
+               *burst_possible = false;
+
+       if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ)
+               *flags |= P54_HDR_FLAG_DATA_OUT_SEQNR;
+
+       if (info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT)
+               *flags |= P54_HDR_FLAG_DATA_OUT_NOCANCEL;
+
+       *queue = skb_get_queue_mapping(skb) + P54_QUEUE_DATA;
+
+       switch (priv->mode) {
+       case NL80211_IFTYPE_MONITOR:
+               /*
+                * We have to set P54_HDR_FLAG_DATA_OUT_PROMISC for
+                * every frame in promiscuous/monitor mode.
+                * see STSW45x0C LMAC API - page 12.
+                */
+               *aid = 0;
+               *flags |= P54_HDR_FLAG_DATA_OUT_PROMISC;
+               break;
+       case NL80211_IFTYPE_STATION:
+               *aid = 1;
+               break;
+       case NL80211_IFTYPE_AP:
+       case NL80211_IFTYPE_ADHOC:
+       case NL80211_IFTYPE_MESH_POINT:
+               if (info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) {
+                       *aid = 0;
+                       *queue = P54_QUEUE_CAB;
+                       return;
+               }
+
+               if (unlikely(ieee80211_is_mgmt(hdr->frame_control))) {
+                       if (ieee80211_is_probe_resp(hdr->frame_control)) {
+                               *aid = 0;
+                               *flags |= P54_HDR_FLAG_DATA_OUT_TIMESTAMP |
+                                         P54_HDR_FLAG_DATA_OUT_NOCANCEL;
+                               return;
+                       } else if (ieee80211_is_beacon(hdr->frame_control)) {
+                               *aid = 0;
+
+                               if (info->flags & IEEE80211_TX_CTL_INJECTED) {
+                                       /*
+                                        * Injecting beacons on top of a AP is
+                                        * not a good idea... nevertheless,
+                                        * it should be doable.
+                                        */
+
+                                       return;
+                               }
+
+                               *flags |= P54_HDR_FLAG_DATA_OUT_TIMESTAMP;
+                               *queue = P54_QUEUE_BEACON;
+                               *extra_len = IEEE80211_MAX_TIM_LEN;
+                               return;
+                       }
+               }
+
+               if (info->control.sta)
+                       *aid = info->control.sta->aid;
+               break;
+       }
+}
+
+static u8 p54_convert_algo(enum ieee80211_key_alg alg)
+{
+       switch (alg) {
+       case ALG_WEP:
+               return P54_CRYPTO_WEP;
+       case ALG_TKIP:
+               return P54_CRYPTO_TKIPMICHAEL;
+       case ALG_CCMP:
+               return P54_CRYPTO_AESCCMP;
+       default:
+               return 0;
+       }
+}
+
+int p54_tx_80211(struct ieee80211_hw *dev, struct sk_buff *skb)
+{
+       struct p54_common *priv = dev->priv;
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+       struct p54_tx_info *p54info;
+       struct p54_hdr *hdr;
+       struct p54_tx_data *txhdr;
+       unsigned int padding, len, extra_len;
+       int i, j, ridx;
+       u16 hdr_flags = 0, aid = 0;
+       u8 rate, queue = 0, crypt_offset = 0;
+       u8 cts_rate = 0x20;
+       u8 rc_flags;
+       u8 calculated_tries[4];
+       u8 nrates = 0, nremaining = 8;
+       bool burst_allowed = false;
+
+       p54_tx_80211_header(priv, skb, info, &queue, &extra_len,
+                           &hdr_flags, &aid, &burst_allowed);
+
+       if (p54_tx_qos_accounting_alloc(priv, skb, queue)) {
+               if (!IS_QOS_QUEUE(queue)) {
+                       dev_kfree_skb_any(skb);
+                       return NETDEV_TX_OK;
+               } else {
+                       return NETDEV_TX_BUSY;
+               }
+       }
+
+       padding = (unsigned long)(skb->data - (sizeof(*hdr) + sizeof(*txhdr))) & 3;
+       len = skb->len;
+
+       if (info->control.hw_key) {
+               crypt_offset = ieee80211_get_hdrlen_from_skb(skb);
+               if (info->control.hw_key->alg == ALG_TKIP) {
+                       u8 *iv = (u8 *)(skb->data + crypt_offset);
+                       /*
+                        * The firmware excepts that the IV has to have
+                        * this special format
+                        */
+                       iv[1] = iv[0];
+                       iv[0] = iv[2];
+                       iv[2] = 0;
+               }
+       }
+
+       txhdr = (struct p54_tx_data *) skb_push(skb, sizeof(*txhdr) + padding);
+       hdr = (struct p54_hdr *) skb_push(skb, sizeof(*hdr));
+
+       if (padding)
+               hdr_flags |= P54_HDR_FLAG_DATA_ALIGN;
+       hdr->type = cpu_to_le16(aid);
+       hdr->rts_tries = info->control.rates[0].count;
+
+       /*
+        * we register the rates in perfect order, and
+        * RTS/CTS won't happen on 5 GHz
+        */
+       cts_rate = info->control.rts_cts_rate_idx;
+
+       memset(&txhdr->rateset, 0, sizeof(txhdr->rateset));
+
+       /* see how many rates got used */
+       for (i = 0; i < dev->max_rates; i++) {
+               if (info->control.rates[i].idx < 0)
+                       break;
+               nrates++;
+       }
+
+       /* limit tries to 8/nrates per rate */
+       for (i = 0; i < nrates; i++) {
+               /*
+                * The magic expression here is equivalent to 8/nrates for
+                * all values that matter, but avoids division and jumps.
+                * Note that nrates can only take the values 1 through 4.
+                */
+               calculated_tries[i] = min_t(int, ((15 >> nrates) | 1) + 1,
+                                                info->control.rates[i].count);
+               nremaining -= calculated_tries[i];
+       }
+
+       /* if there are tries left, distribute from back to front */
+       for (i = nrates - 1; nremaining > 0 && i >= 0; i--) {
+               int tmp = info->control.rates[i].count - calculated_tries[i];
+
+               if (tmp <= 0)
+                       continue;
+               /* RC requested more tries at this rate */
+
+               tmp = min_t(int, tmp, nremaining);
+               calculated_tries[i] += tmp;
+               nremaining -= tmp;
+       }
+
+       ridx = 0;
+       for (i = 0; i < nrates && ridx < 8; i++) {
+               /* we register the rates in perfect order */
+               rate = info->control.rates[i].idx;
+               if (info->band == IEEE80211_BAND_5GHZ)
+                       rate += 4;
+
+               /* store the count we actually calculated for TX status */
+               info->control.rates[i].count = calculated_tries[i];
+
+               rc_flags = info->control.rates[i].flags;
+               if (rc_flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) {
+                       rate |= 0x10;
+                       cts_rate |= 0x10;
+               }
+               if (rc_flags & IEEE80211_TX_RC_USE_RTS_CTS) {
+                       burst_allowed = false;
+                       rate |= 0x40;
+               } else if (rc_flags & IEEE80211_TX_RC_USE_CTS_PROTECT) {
+                       rate |= 0x20;
+                       burst_allowed = false;
+               }
+               for (j = 0; j < calculated_tries[i] && ridx < 8; j++) {
+                       txhdr->rateset[ridx] = rate;
+                       ridx++;
+               }
+       }
+
+       if (burst_allowed)
+               hdr_flags |= P54_HDR_FLAG_DATA_OUT_BURST;
+
+       /* TODO: enable bursting */
+       hdr->flags = cpu_to_le16(hdr_flags);
+       hdr->tries = ridx;
+       txhdr->rts_rate_idx = 0;
+       if (info->control.hw_key) {
+               txhdr->key_type = p54_convert_algo(info->control.hw_key->alg);
+               txhdr->key_len = min((u8)16, info->control.hw_key->keylen);
+               memcpy(txhdr->key, info->control.hw_key->key, txhdr->key_len);
+               if (info->control.hw_key->alg == ALG_TKIP) {
+                       /* reserve space for the MIC key */
+                       len += 8;
+                       memcpy(skb_put(skb, 8), &(info->control.hw_key->key
+                               [NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY]), 8);
+               }
+               /* reserve some space for ICV */
+               len += info->control.hw_key->icv_len;
+               memset(skb_put(skb, info->control.hw_key->icv_len), 0,
+                      info->control.hw_key->icv_len);
+       } else {
+               txhdr->key_type = 0;
+               txhdr->key_len = 0;
+       }
+       txhdr->crypt_offset = crypt_offset;
+       txhdr->hw_queue = queue;
+       txhdr->backlog = priv->tx_stats[queue].len - 1;
+       memset(txhdr->durations, 0, sizeof(txhdr->durations));
+       txhdr->tx_antenna = ((info->antenna_sel_tx == 0) ?
+               2 : info->antenna_sel_tx - 1) & priv->tx_diversity_mask;
+       if (priv->rxhw == 5) {
+               txhdr->longbow.cts_rate = cts_rate;
+               txhdr->longbow.output_power = cpu_to_le16(priv->output_power);
+       } else {
+               txhdr->normal.output_power = priv->output_power;
+               txhdr->normal.cts_rate = cts_rate;
+       }
+       if (padding)
+               txhdr->align[0] = padding;
+
+       hdr->len = cpu_to_le16(len);
+       /* modifies skb->cb and with it info, so must be last! */
+       p54info = (void *) info->rate_driver_data;
+       p54info->extra_len = extra_len;
+
+       p54_tx(priv, skb);
+       return NETDEV_TX_OK;
+}
index 8f62109..c255d9c 100644 (file)
@@ -234,7 +234,7 @@ islpci_eth_transmit(struct sk_buff *skb, struct net_device *ndev)
        /* unlock the driver code */
        spin_unlock_irqrestore(&priv->slock, flags);
 
-       return 0;
+       return NETDEV_TX_OK;
 
       drop_free:
        ndev->stats.tx_dropped++;
index 3087672..83d3662 100644 (file)
@@ -49,9 +49,7 @@ static const struct pci_device_id prism54_id_tbl[] = {
 
        /* 3COM 3CRWE154G72 Wireless LAN adapter */
        {
-        0x10b7, 0x6001,
-        PCI_ANY_ID, PCI_ANY_ID,
-        0, 0, 0
+        PCI_VDEVICE(3COM, 0x6001), 0
        },
 
        /* Intersil PRISM Indigo Wireless LAN adapter */
index b10b038..64e574c 100644 (file)
@@ -937,7 +937,7 @@ static int ray_dev_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
        if (length < ETH_ZLEN) {
                if (skb_padto(skb, ETH_ZLEN))
-                       return 0;
+                       return NETDEV_TX_OK;
                length = ETH_ZLEN;
        }
        switch (ray_hw_xmit(skb->data, length, dev, DATA_TYPE)) {
@@ -951,9 +951,9 @@ static int ray_dev_start_xmit(struct sk_buff *skb, struct net_device *dev)
        default:
                dev->trans_start = jiffies;
                dev_kfree_skb(skb);
-               return 0;
+               return NETDEV_TX_OK;
        }
-       return 0;
+       return NETDEV_TX_OK;
 } /* ray_dev_start_xmit */
 
 /*===========================================================================*/
index 3bec3db..09c0702 100644 (file)
@@ -139,9 +139,15 @@ MODULE_PARM_DESC(workaround_interval,
 /* Assume that Broadcom 4320 (only chipset at time of writing known to be
  * based on wireless rndis) has default txpower of 13dBm.
  * This value is from Linksys WUSB54GSC User Guide, Appendix F: Specifications.
- *   13dBm == 19.9mW
+ *  100% : 20 mW ~ 13dBm
+ *   75% : 15 mW ~ 12dBm
+ *   50% : 10 mW ~ 10dBm
+ *   25% :  5 mW ~  7dBm
  */
-#define BCM4320_DEFAULT_TXPOWER 20
+#define BCM4320_DEFAULT_TXPOWER_DBM_100 13
+#define BCM4320_DEFAULT_TXPOWER_DBM_75  12
+#define BCM4320_DEFAULT_TXPOWER_DBM_50  10
+#define BCM4320_DEFAULT_TXPOWER_DBM_25  7
 
 
 /* codes for "status" field of completion messages */
@@ -420,21 +426,30 @@ struct rndis_wlan_private {
 /*
  * cfg80211 ops
  */
-static int rndis_change_virtual_intf(struct wiphy *wiphy, int ifindex,
+static int rndis_change_virtual_intf(struct wiphy *wiphy,
+                                       struct net_device *dev,
                                        enum nl80211_iftype type, u32 *flags,
                                        struct vif_params *params);
 
 static int rndis_scan(struct wiphy *wiphy, struct net_device *dev,
                        struct cfg80211_scan_request *request);
 
+static int rndis_set_wiphy_params(struct wiphy *wiphy, u32 changed);
+
+static int rndis_set_tx_power(struct wiphy *wiphy, enum tx_power_setting type,
+                               int dbm);
+static int rndis_get_tx_power(struct wiphy *wiphy, int *dbm);
+
 static struct cfg80211_ops rndis_config_ops = {
        .change_virtual_intf = rndis_change_virtual_intf,
        .scan = rndis_scan,
+       .set_wiphy_params = rndis_set_wiphy_params,
+       .set_tx_power = rndis_set_tx_power,
+       .get_tx_power = rndis_get_tx_power,
 };
 
 static void *rndis_wiphy_privid = &rndis_wiphy_privid;
 
-static const int bcm4320_power_output[4] = { 25, 50, 75, 100 };
 
 static const unsigned char zero_bssid[ETH_ALEN] = {0,};
 static const unsigned char ffff_bssid[ETH_ALEN] = { 0xff, 0xff, 0xff,
@@ -447,10 +462,19 @@ static struct rndis_wlan_private *get_rndis_wlan_priv(struct usbnet *dev)
 }
 
 
-static u32 get_bcm4320_power(struct rndis_wlan_private *priv)
+static u32 get_bcm4320_power_dbm(struct rndis_wlan_private *priv)
 {
-       return BCM4320_DEFAULT_TXPOWER *
-               bcm4320_power_output[priv->param_power_output] / 100;
+       switch (priv->param_power_output) {
+       default:
+       case 3:
+               return BCM4320_DEFAULT_TXPOWER_DBM_100;
+       case 2:
+               return BCM4320_DEFAULT_TXPOWER_DBM_75;
+       case 1:
+               return BCM4320_DEFAULT_TXPOWER_DBM_50;
+       case 0:
+               return BCM4320_DEFAULT_TXPOWER_DBM_25;
+       }
 }
 
 
@@ -968,6 +992,36 @@ static int set_infra_mode(struct usbnet *usbdev, int mode)
 }
 
 
+static int set_rts_threshold(struct usbnet *usbdev, u32 rts_threshold)
+{
+       __le32 tmp;
+
+       devdbg(usbdev, "set_rts_threshold %i", rts_threshold);
+
+       if (rts_threshold < 0 || rts_threshold > 2347)
+               rts_threshold = 2347;
+
+       tmp = cpu_to_le32(rts_threshold);
+       return rndis_set_oid(usbdev, OID_802_11_RTS_THRESHOLD, &tmp,
+                                                               sizeof(tmp));
+}
+
+
+static int set_frag_threshold(struct usbnet *usbdev, u32 frag_threshold)
+{
+       __le32 tmp;
+
+       devdbg(usbdev, "set_frag_threshold %i", frag_threshold);
+
+       if (frag_threshold < 256 || frag_threshold > 2346)
+               frag_threshold = 2346;
+
+       tmp = cpu_to_le32(frag_threshold);
+       return rndis_set_oid(usbdev, OID_802_11_FRAGMENTATION_THRESHOLD, &tmp,
+                                                               sizeof(tmp));
+}
+
+
 static void set_default_iw_params(struct usbnet *usbdev)
 {
        struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
@@ -1222,20 +1276,14 @@ static void set_multicast_list(struct usbnet *usbdev)
 /*
  * cfg80211 ops
  */
-static int rndis_change_virtual_intf(struct wiphy *wiphy, int ifindex,
+static int rndis_change_virtual_intf(struct wiphy *wiphy,
+                                       struct net_device *dev,
                                        enum nl80211_iftype type, u32 *flags,
                                        struct vif_params *params)
 {
-       struct net_device *dev;
-       struct usbnet *usbdev;
+       struct usbnet *usbdev = netdev_priv(dev);
        int mode;
 
-       /* we're under RTNL */
-       dev = __dev_get_by_index(&init_net, ifindex);
-       if (!dev)
-               return -ENODEV;
-       usbdev = netdev_priv(dev);
-
        switch (type) {
        case NL80211_IFTYPE_ADHOC:
                mode = NDIS_80211_INFRA_ADHOC;
@@ -1251,6 +1299,64 @@ static int rndis_change_virtual_intf(struct wiphy *wiphy, int ifindex,
 }
 
 
+static int rndis_set_wiphy_params(struct wiphy *wiphy, u32 changed)
+{
+       struct rndis_wlan_private *priv = wiphy_priv(wiphy);
+       struct usbnet *usbdev = priv->usbdev;
+       int err;
+
+       if (changed & WIPHY_PARAM_FRAG_THRESHOLD) {
+               err = set_frag_threshold(usbdev, wiphy->frag_threshold);
+               if (err < 0)
+                       return err;
+       }
+
+       if (changed & WIPHY_PARAM_RTS_THRESHOLD) {
+               err = set_rts_threshold(usbdev, wiphy->rts_threshold);
+               if (err < 0)
+                       return err;
+       }
+
+       return 0;
+}
+
+
+static int rndis_set_tx_power(struct wiphy *wiphy, enum tx_power_setting type,
+                               int dbm)
+{
+       struct rndis_wlan_private *priv = wiphy_priv(wiphy);
+       struct usbnet *usbdev = priv->usbdev;
+
+       devdbg(usbdev, "rndis_set_tx_power type:0x%x dbm:%i", type, dbm);
+
+       /* Device doesn't support changing txpower after initialization, only
+        * turn off/on radio. Support 'auto' mode and setting same dBm that is
+        * currently used.
+        */
+       if (type == TX_POWER_AUTOMATIC || dbm == get_bcm4320_power_dbm(priv)) {
+               if (!priv->radio_on)
+                       disassociate(usbdev, 1); /* turn on radio */
+
+               return 0;
+       }
+
+       return -ENOTSUPP;
+}
+
+
+static int rndis_get_tx_power(struct wiphy *wiphy, int *dbm)
+{
+       struct rndis_wlan_private *priv = wiphy_priv(wiphy);
+       struct usbnet *usbdev = priv->usbdev;
+
+       *dbm = get_bcm4320_power_dbm(priv);
+
+       devdbg(usbdev, "rndis_get_tx_power dbm:%i", *dbm);
+
+       return 0;
+}
+
+
 #define SCAN_DELAY_JIFFIES (HZ)
 static int rndis_scan(struct wiphy *wiphy, struct net_device *dev,
                        struct cfg80211_scan_request *request)
@@ -1766,74 +1872,6 @@ static int rndis_iw_get_genie(struct net_device *dev,
 }
 
 
-static int rndis_iw_set_rts(struct net_device *dev,
-    struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
-{
-       struct usbnet *usbdev = netdev_priv(dev);
-       __le32 tmp;
-       devdbg(usbdev, "SIOCSIWRTS");
-
-       tmp = cpu_to_le32(wrqu->rts.value);
-       return rndis_set_oid(usbdev, OID_802_11_RTS_THRESHOLD, &tmp,
-                                                               sizeof(tmp));
-}
-
-
-static int rndis_iw_get_rts(struct net_device *dev,
-    struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
-{
-       struct usbnet *usbdev = netdev_priv(dev);
-       __le32 tmp;
-       int len, ret;
-
-       len = sizeof(tmp);
-       ret = rndis_query_oid(usbdev, OID_802_11_RTS_THRESHOLD, &tmp, &len);
-       if (ret == 0) {
-               wrqu->rts.value = le32_to_cpu(tmp);
-               wrqu->rts.flags = 1;
-               wrqu->rts.disabled = 0;
-       }
-
-       devdbg(usbdev, "SIOCGIWRTS: %d", wrqu->rts.value);
-
-       return ret;
-}
-
-
-static int rndis_iw_set_frag(struct net_device *dev,
-    struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
-{
-       struct usbnet *usbdev = netdev_priv(dev);
-       __le32 tmp;
-
-       devdbg(usbdev, "SIOCSIWFRAG");
-
-       tmp = cpu_to_le32(wrqu->frag.value);
-       return rndis_set_oid(usbdev, OID_802_11_FRAGMENTATION_THRESHOLD, &tmp,
-                                                               sizeof(tmp));
-}
-
-
-static int rndis_iw_get_frag(struct net_device *dev,
-    struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
-{
-       struct usbnet *usbdev = netdev_priv(dev);
-       __le32 tmp;
-       int len, ret;
-
-       len = sizeof(tmp);
-       ret = rndis_query_oid(usbdev, OID_802_11_FRAGMENTATION_THRESHOLD, &tmp,
-                                                                       &len);
-       if (ret == 0) {
-               wrqu->frag.value = le32_to_cpu(tmp);
-               wrqu->frag.flags = 1;
-               wrqu->frag.disabled = 0;
-       }
-       devdbg(usbdev, "SIOCGIWFRAG: %d", wrqu->frag.value);
-       return ret;
-}
-
-
 static int rndis_iw_set_freq(struct net_device *dev,
     struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
 {
@@ -1882,71 +1920,6 @@ static int rndis_iw_get_freq(struct net_device *dev,
 }
 
 
-static int rndis_iw_get_txpower(struct net_device *dev,
-    struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
-{
-       struct usbnet *usbdev = netdev_priv(dev);
-       struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
-       __le32 tx_power;
-
-       if (priv->radio_on) {
-               /* fake since changing tx_power (by userlevel) not supported */
-               tx_power = cpu_to_le32(get_bcm4320_power(priv));
-
-               wrqu->txpower.flags = IW_TXPOW_MWATT;
-               wrqu->txpower.value = le32_to_cpu(tx_power);
-               wrqu->txpower.disabled = 0;
-       } else {
-               wrqu->txpower.flags = IW_TXPOW_MWATT;
-               wrqu->txpower.value = 0;
-               wrqu->txpower.disabled = 1;
-       }
-
-       devdbg(usbdev, "SIOCGIWTXPOW: %d", wrqu->txpower.value);
-
-       return 0;
-}
-
-
-static int rndis_iw_set_txpower(struct net_device *dev,
-    struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
-{
-       struct usbnet *usbdev = netdev_priv(dev);
-       struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
-       __le32 tx_power = 0;
-
-       if (!wrqu->txpower.disabled) {
-               if (wrqu->txpower.flags == IW_TXPOW_MWATT)
-                       tx_power = cpu_to_le32(wrqu->txpower.value);
-               else { /* wrqu->txpower.flags == IW_TXPOW_DBM */
-                       if (wrqu->txpower.value > 20)
-                               tx_power = cpu_to_le32(128);
-                       else if (wrqu->txpower.value < -43)
-                               tx_power = cpu_to_le32(127);
-                       else {
-                               signed char tmp;
-                               tmp = wrqu->txpower.value;
-                               tmp = -12 - tmp;
-                               tmp <<= 2;
-                               tx_power = cpu_to_le32((unsigned char)tmp);
-                       }
-               }
-       }
-
-       devdbg(usbdev, "SIOCSIWTXPOW: %d", le32_to_cpu(tx_power));
-
-       if (le32_to_cpu(tx_power) != 0) {
-               /* txpower unsupported, just turn radio on */
-               if (!priv->radio_on)
-                       return disassociate(usbdev, 1);
-               return 0; /* all ready on */
-       }
-
-       /* tx_power == 0, turn off radio */
-       return disassociate(usbdev, 0);
-}
-
-
 static int rndis_iw_get_rate(struct net_device *dev,
     struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
 {
@@ -2022,12 +1995,12 @@ static const iw_handler rndis_iw_handler[] =
        IW_IOCTL(SIOCSIWESSID)     = rndis_iw_set_essid,
        IW_IOCTL(SIOCGIWESSID)     = rndis_iw_get_essid,
        IW_IOCTL(SIOCGIWRATE)      = rndis_iw_get_rate,
-       IW_IOCTL(SIOCSIWRTS)       = rndis_iw_set_rts,
-       IW_IOCTL(SIOCGIWRTS)       = rndis_iw_get_rts,
-       IW_IOCTL(SIOCSIWFRAG)      = rndis_iw_set_frag,
-       IW_IOCTL(SIOCGIWFRAG)      = rndis_iw_get_frag,
-       IW_IOCTL(SIOCSIWTXPOW)     = rndis_iw_set_txpower,
-       IW_IOCTL(SIOCGIWTXPOW)     = rndis_iw_get_txpower,
+       IW_IOCTL(SIOCSIWRTS)       = (iw_handler) cfg80211_wext_siwrts,
+       IW_IOCTL(SIOCGIWRTS)       = (iw_handler) cfg80211_wext_giwrts,
+       IW_IOCTL(SIOCSIWFRAG)      = (iw_handler) cfg80211_wext_siwfrag,
+       IW_IOCTL(SIOCGIWFRAG)      = (iw_handler) cfg80211_wext_giwfrag,
+       IW_IOCTL(SIOCSIWTXPOW)     = (iw_handler) cfg80211_wext_siwtxpower,
+       IW_IOCTL(SIOCGIWTXPOW)     = (iw_handler) cfg80211_wext_giwtxpower,
        IW_IOCTL(SIOCSIWENCODE)    = rndis_iw_set_encode,
        IW_IOCTL(SIOCSIWENCODEEXT) = rndis_iw_set_encode_ext,
        IW_IOCTL(SIOCSIWAUTH)      = rndis_iw_set_auth,
@@ -2475,6 +2448,10 @@ static int rndis_wlan_bind(struct usbnet *usbdev, struct usb_interface *intf)
 
        set_default_iw_params(usbdev);
 
+       /* set default rts/frag */
+       rndis_set_wiphy_params(wiphy,
+                       WIPHY_PARAM_FRAG_THRESHOLD | WIPHY_PARAM_RTS_THRESHOLD);
+
        /* turn radio on */
        priv->radio_on = 1;
        disassociate(usbdev, 1);
@@ -2522,10 +2499,18 @@ static void rndis_wlan_unbind(struct usbnet *usbdev, struct usb_interface *intf)
 
 static int rndis_wlan_reset(struct usbnet *usbdev)
 {
+       devdbg(usbdev, "rndis_wlan_reset");
        return deauthenticate(usbdev);
 }
 
 
+static int rndis_wlan_stop(struct usbnet *usbdev)
+{
+       devdbg(usbdev, "rndis_wlan_stop");
+       return disassociate(usbdev, 0);
+}
+
+
 static const struct driver_info        bcm4320b_info = {
        .description =  "Wireless RNDIS device, BCM4320b based",
        .flags =        FLAG_WLAN | FLAG_FRAMING_RN | FLAG_NO_SETINT,
@@ -2535,6 +2520,7 @@ static const struct driver_info   bcm4320b_info = {
        .rx_fixup =     rndis_rx_fixup,
        .tx_fixup =     rndis_tx_fixup,
        .reset =        rndis_wlan_reset,
+       .stop =         rndis_wlan_stop,
        .early_init =   bcm4320b_early_init,
        .link_change =  rndis_wlan_link_change,
 };
@@ -2548,6 +2534,7 @@ static const struct driver_info   bcm4320a_info = {
        .rx_fixup =     rndis_rx_fixup,
        .tx_fixup =     rndis_tx_fixup,
        .reset =        rndis_wlan_reset,
+       .stop =         rndis_wlan_stop,
        .early_init =   bcm4320a_early_init,
        .link_change =  rndis_wlan_link_change,
 };
@@ -2561,6 +2548,7 @@ static const struct driver_info rndis_wlan_info = {
        .rx_fixup =     rndis_rx_fixup,
        .tx_fixup =     rndis_tx_fixup,
        .reset =        rndis_wlan_reset,
+       .stop =         rndis_wlan_stop,
        .early_init =   bcm4320a_early_init,
        .link_change =  rndis_wlan_link_change,
 };
index 8aab3e6..f970aa2 100644 (file)
@@ -112,14 +112,6 @@ config RT2X00_LIB_FIRMWARE
 config RT2X00_LIB_CRYPTO
        boolean
 
-config RT2X00_LIB_RFKILL
-       boolean
-       default y if (RT2X00_LIB=y && INPUT=y) || (RT2X00_LIB=m && INPUT!=n)
-       select INPUT_POLLDEV
-
-comment "rt2x00 rfkill support disabled due to modularized INPUT and built-in rt2x00"
-       depends on RT2X00_LIB=y && INPUT=m
-
 config RT2X00_LIB_LEDS
        boolean
        default y if (RT2X00_LIB=y && LEDS_CLASS=y) || (RT2X00_LIB=m && LEDS_CLASS!=n)
index bfc7226..13043ea 100644 (file)
@@ -5,7 +5,6 @@ rt2x00lib-y                             += rt2x00queue.o
 rt2x00lib-y                            += rt2x00link.o
 rt2x00lib-$(CONFIG_RT2X00_LIB_DEBUGFS) += rt2x00debug.o
 rt2x00lib-$(CONFIG_RT2X00_LIB_CRYPTO)  += rt2x00crypto.o
-rt2x00lib-$(CONFIG_RT2X00_LIB_RFKILL)  += rt2x00rfkill.o
 rt2x00lib-$(CONFIG_RT2X00_LIB_FIRMWARE)        += rt2x00firmware.o
 rt2x00lib-$(CONFIG_RT2X00_LIB_LEDS)    += rt2x00leds.o
 rt2x00lib-$(CONFIG_RT2X00_LIB_HT)      += rt2x00ht.o
index 435f945..d8035e3 100644 (file)
@@ -199,7 +199,6 @@ static const struct rt2x00debug rt2400pci_rt2x00debug = {
 };
 #endif /* CONFIG_RT2X00_LIB_DEBUGFS */
 
-#ifdef CONFIG_RT2X00_LIB_RFKILL
 static int rt2400pci_rfkill_poll(struct rt2x00_dev *rt2x00dev)
 {
        u32 reg;
@@ -207,9 +206,6 @@ static int rt2400pci_rfkill_poll(struct rt2x00_dev *rt2x00dev)
        rt2x00pci_register_read(rt2x00dev, GPIOCSR, &reg);
        return rt2x00_get_field32(reg, GPIOCSR_BIT0);
 }
-#else
-#define rt2400pci_rfkill_poll  NULL
-#endif /* CONFIG_RT2X00_LIB_RFKILL */
 
 #ifdef CONFIG_RT2X00_LIB_LEDS
 static void rt2400pci_brightness_set(struct led_classdev *led_cdev,
@@ -1391,10 +1387,8 @@ static int rt2400pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
        /*
         * Detect if this device has an hardware controlled radio.
         */
-#ifdef CONFIG_RT2X00_LIB_RFKILL
        if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO))
                __set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags);
-#endif /* CONFIG_RT2X00_LIB_RFKILL */
 
        /*
         * Check if the BBP tuning should be enabled.
@@ -1573,6 +1567,7 @@ static const struct ieee80211_ops rt2400pci_mac80211_ops = {
        .get_tx_stats           = rt2x00mac_get_tx_stats,
        .get_tsf                = rt2400pci_get_tsf,
        .tx_last_beacon         = rt2400pci_tx_last_beacon,
+       .rfkill_poll            = rt2x00mac_rfkill_poll,
 };
 
 static const struct rt2x00lib_ops rt2400pci_rt2x00_ops = {
index 08b30d0..c123e28 100644 (file)
@@ -199,7 +199,6 @@ static const struct rt2x00debug rt2500pci_rt2x00debug = {
 };
 #endif /* CONFIG_RT2X00_LIB_DEBUGFS */
 
-#ifdef CONFIG_RT2X00_LIB_RFKILL
 static int rt2500pci_rfkill_poll(struct rt2x00_dev *rt2x00dev)
 {
        u32 reg;
@@ -207,9 +206,6 @@ static int rt2500pci_rfkill_poll(struct rt2x00_dev *rt2x00dev)
        rt2x00pci_register_read(rt2x00dev, GPIOCSR, &reg);
        return rt2x00_get_field32(reg, GPIOCSR_BIT0);
 }
-#else
-#define rt2500pci_rfkill_poll  NULL
-#endif /* CONFIG_RT2X00_LIB_RFKILL */
 
 #ifdef CONFIG_RT2X00_LIB_LEDS
 static void rt2500pci_brightness_set(struct led_classdev *led_cdev,
@@ -1548,10 +1544,8 @@ static int rt2500pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
        /*
         * Detect if this device has an hardware controlled radio.
         */
-#ifdef CONFIG_RT2X00_LIB_RFKILL
        if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO))
                __set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags);
-#endif /* CONFIG_RT2X00_LIB_RFKILL */
 
        /*
         * Check if the BBP tuning should be enabled.
@@ -1872,6 +1866,7 @@ static const struct ieee80211_ops rt2500pci_mac80211_ops = {
        .get_tx_stats           = rt2x00mac_get_tx_stats,
        .get_tsf                = rt2500pci_get_tsf,
        .tx_last_beacon         = rt2500pci_tx_last_beacon,
+       .rfkill_poll            = rt2x00mac_rfkill_poll,
 };
 
 static const struct rt2x00lib_ops rt2500pci_rt2x00_ops = {
index ce75426..00611b3 100644 (file)
@@ -277,7 +277,6 @@ static const struct rt2x00debug rt2500usb_rt2x00debug = {
 };
 #endif /* CONFIG_RT2X00_LIB_DEBUGFS */
 
-#ifdef CONFIG_RT2X00_LIB_RFKILL
 static int rt2500usb_rfkill_poll(struct rt2x00_dev *rt2x00dev)
 {
        u16 reg;
@@ -285,9 +284,6 @@ static int rt2500usb_rfkill_poll(struct rt2x00_dev *rt2x00dev)
        rt2500usb_register_read(rt2x00dev, MAC_CSR19, &reg);
        return rt2x00_get_field32(reg, MAC_CSR19_BIT7);
 }
-#else
-#define rt2500usb_rfkill_poll  NULL
-#endif /* CONFIG_RT2X00_LIB_RFKILL */
 
 #ifdef CONFIG_RT2X00_LIB_LEDS
 static void rt2500usb_brightness_set(struct led_classdev *led_cdev,
@@ -1603,10 +1599,8 @@ static int rt2500usb_init_eeprom(struct rt2x00_dev *rt2x00dev)
        /*
         * Detect if this device has an hardware controlled radio.
         */
-#ifdef CONFIG_RT2X00_LIB_RFKILL
        if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO))
                __set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags);
-#endif /* CONFIG_RT2X00_LIB_RFKILL */
 
        /*
         * Check if the BBP tuning should be disabled.
@@ -1907,6 +1901,7 @@ static const struct ieee80211_ops rt2500usb_mac80211_ops = {
        .bss_info_changed       = rt2x00mac_bss_info_changed,
        .conf_tx                = rt2x00mac_conf_tx,
        .get_tx_stats           = rt2x00mac_get_tx_stats,
+       .rfkill_poll            = rt2x00mac_rfkill_poll,
 };
 
 static const struct rt2x00lib_ops rt2500usb_rt2x00_ops = {
index 3756166..a204e66 100644 (file)
@@ -264,7 +264,6 @@ static const struct rt2x00debug rt2800usb_rt2x00debug = {
 };
 #endif /* CONFIG_RT2X00_LIB_DEBUGFS */
 
-#ifdef CONFIG_RT2X00_LIB_RFKILL
 static int rt2800usb_rfkill_poll(struct rt2x00_dev *rt2x00dev)
 {
        u32 reg;
@@ -272,9 +271,6 @@ static int rt2800usb_rfkill_poll(struct rt2x00_dev *rt2x00dev)
        rt2x00usb_register_read(rt2x00dev, GPIO_CTRL_CFG, &reg);
        return rt2x00_get_field32(reg, GPIO_CTRL_CFG_BIT2);
 }
-#else
-#define rt2800usb_rfkill_poll  NULL
-#endif /* CONFIG_RT2X00_LIB_RFKILL */
 
 #ifdef CONFIG_RT2X00_LIB_LEDS
 static void rt2800usb_brightness_set(struct led_classdev *led_cdev,
@@ -2385,10 +2381,8 @@ static int rt2800usb_init_eeprom(struct rt2x00_dev *rt2x00dev)
        /*
         * Detect if this device has an hardware controlled radio.
         */
-#ifdef CONFIG_RT2X00_LIB_RFKILL
        if (rt2x00_get_field16(eeprom, EEPROM_NIC_HW_RADIO))
                __set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags);
-#endif /* CONFIG_RT2X00_LIB_RFKILL */
 
        /*
         * Store led settings, for correct led behaviour.
@@ -2800,6 +2794,7 @@ static const struct ieee80211_ops rt2800usb_mac80211_ops = {
        .conf_tx                = rt2800usb_conf_tx,
        .get_tx_stats           = rt2x00mac_get_tx_stats,
        .get_tsf                = rt2800usb_get_tsf,
+       .rfkill_poll            = rt2x00mac_rfkill_poll,
 };
 
 static const struct rt2x00lib_ops rt2800usb_rt2x00_ops = {
index a498dde..71f37cb 100644 (file)
@@ -651,18 +651,6 @@ struct rt2x00_dev {
        enum ieee80211_band curr_band;
 
        /*
-        * rfkill structure for RF state switching support.
-        * This will only be compiled in when required.
-        */
-#ifdef CONFIG_RT2X00_LIB_RFKILL
-       unsigned long rfkill_state;
-#define RFKILL_STATE_ALLOCATED         1
-#define RFKILL_STATE_REGISTERED                2
-#define RFKILL_STATE_BLOCKED           3
-       struct input_polled_dev *rfkill_poll_dev;
-#endif /* CONFIG_RT2X00_LIB_RFKILL */
-
-       /*
         * If enabled, the debugfs interface structures
         * required for deregistration of debugfs.
         */
@@ -992,6 +980,7 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw,
                                u32 changes);
 int rt2x00mac_conf_tx(struct ieee80211_hw *hw, u16 queue,
                      const struct ieee80211_tx_queue_params *params);
+void rt2x00mac_rfkill_poll(struct ieee80211_hw *hw);
 
 /*
  * Driver allocation handlers.
index bc4e81e..c54eda3 100644 (file)
@@ -53,8 +53,7 @@ void rt2x00crypto_create_tx_descriptor(struct queue_entry *entry,
        struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(entry->skb);
        struct ieee80211_key_conf *hw_key = tx_info->control.hw_key;
 
-       if (!test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags) ||
-           !hw_key || entry->skb->do_not_encrypt)
+       if (!test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags) || !hw_key)
                return;
 
        __set_bit(ENTRY_TXD_ENCRYPT, &txdesc->flags);
@@ -82,8 +81,7 @@ unsigned int rt2x00crypto_tx_overhead(struct rt2x00_dev *rt2x00dev,
        struct ieee80211_key_conf *key = tx_info->control.hw_key;
        unsigned int overhead = 0;
 
-       if (!test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags) ||
-           !key || skb->do_not_encrypt)
+       if (!test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags) || !key)
                return overhead;
 
        /*
index 57813e7..4fff3a8 100644 (file)
@@ -449,7 +449,8 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev,
         * mac80211 will clean up the skb structure.
         */
        rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_RXDONE, entry->skb);
-       ieee80211_rx_irqsafe(rt2x00dev->hw, entry->skb, rx_status);
+       memcpy(IEEE80211_SKB_RXCB(entry->skb), rx_status, sizeof(*rx_status));
+       ieee80211_rx_irqsafe(rt2x00dev->hw, entry->skb);
 
        /*
         * Replace the skb with the freshly allocated one.
@@ -870,7 +871,6 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev)
         */
        rt2x00link_register(rt2x00dev);
        rt2x00leds_register(rt2x00dev);
-       rt2x00rfkill_allocate(rt2x00dev);
        rt2x00debug_register(rt2x00dev);
 
        set_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags);
@@ -902,7 +902,6 @@ void rt2x00lib_remove_dev(struct rt2x00_dev *rt2x00dev)
         * Free extra components
         */
        rt2x00debug_deregister(rt2x00dev);
-       rt2x00rfkill_free(rt2x00dev);
        rt2x00leds_unregister(rt2x00dev);
 
        /*
index 0bf2715..512fa2b 100644 (file)
 
 /*
  * Interval defines
- * Both the link tuner as the rfkill will be called once per second.
  */
 #define LINK_TUNE_INTERVAL     round_jiffies_relative(HZ)
-#define RFKILL_POLL_INTERVAL   1000
 
 /*
  * rt2x00_rate: Per rate device information
@@ -386,29 +384,18 @@ static inline void rt2x00ht_create_tx_descriptor(struct queue_entry *entry,
 /*
  * RFkill handlers.
  */
-#ifdef CONFIG_RT2X00_LIB_RFKILL
-void rt2x00rfkill_register(struct rt2x00_dev *rt2x00dev);
-void rt2x00rfkill_unregister(struct rt2x00_dev *rt2x00dev);
-void rt2x00rfkill_allocate(struct rt2x00_dev *rt2x00dev);
-void rt2x00rfkill_free(struct rt2x00_dev *rt2x00dev);
-#else
 static inline void rt2x00rfkill_register(struct rt2x00_dev *rt2x00dev)
 {
+       if (test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags))
+               wiphy_rfkill_start_polling(rt2x00dev->hw->wiphy);
 }
 
 static inline void rt2x00rfkill_unregister(struct rt2x00_dev *rt2x00dev)
 {
+       if (test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags))
+               wiphy_rfkill_stop_polling(rt2x00dev->hw->wiphy);
 }
 
-static inline void rt2x00rfkill_allocate(struct rt2x00_dev *rt2x00dev)
-{
-}
-
-static inline void rt2x00rfkill_free(struct rt2x00_dev *rt2x00dev)
-{
-}
-#endif /* CONFIG_RT2X00_LIB_RFKILL */
-
 /*
  * LED handlers
  */
index c4c06b4..b7e0ddd 100644 (file)
@@ -73,7 +73,8 @@ static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev,
        else
                rts_info->flags &= ~IEEE80211_TX_CTL_NO_ACK;
 
-       skb->do_not_encrypt = 1;
+       /* Disable hardware encryption */
+       rts_info->control.hw_key = NULL;
 
        /*
         * RTS/CTS frame should use the length of the frame plus any
@@ -687,3 +688,12 @@ int rt2x00mac_conf_tx(struct ieee80211_hw *hw, u16 queue_idx,
        return 0;
 }
 EXPORT_SYMBOL_GPL(rt2x00mac_conf_tx);
+
+void rt2x00mac_rfkill_poll(struct ieee80211_hw *hw)
+{
+       struct rt2x00_dev *rt2x00dev = hw->priv;
+       bool blocked = !!rt2x00dev->ops->lib->rfkill_poll(rt2x00dev);
+
+       wiphy_rfkill_set_hw_state(hw->wiphy, blocked);
+}
+EXPORT_SYMBOL_GPL(rt2x00mac_rfkill_poll);
diff --git a/drivers/net/wireless/rt2x00/rt2x00rfkill.c b/drivers/net/wireless/rt2x00/rt2x00rfkill.c
deleted file mode 100644 (file)
index b6d4c67..0000000
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
-       Copyright (C) 2004 - 2009 rt2x00 SourceForge Project
-       <http://rt2x00.serialmonkey.com>
-
-       This program is free software; you can redistribute it and/or modify
-       it under the terms of the GNU General Public License as published by
-       the Free Software Foundation; either version 2 of the License, or
-       (at your option) any later version.
-
-       This program is distributed in the hope that it will be useful,
-       but WITHOUT ANY WARRANTY; without even the implied warranty of
-       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-       GNU General Public License for more details.
-
-       You should have received a copy of the GNU General Public License
-       along with this program; if not, write to the
-       Free Software Foundation, Inc.,
-       59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-/*
-       Module: rt2x00rfkill
-       Abstract: rt2x00 rfkill routines.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-
-#include "rt2x00.h"
-#include "rt2x00lib.h"
-
-static void rt2x00rfkill_poll(struct input_polled_dev *poll_dev)
-{
-       struct rt2x00_dev *rt2x00dev = poll_dev->private;
-       int state, old_state;
-
-       if (!test_bit(RFKILL_STATE_REGISTERED, &rt2x00dev->rfkill_state) ||
-           !test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags))
-               return;
-
-       /*
-        * Poll latest state, if the state is different then the previous state,
-        * we should generate an input event.
-        */
-       state = !!rt2x00dev->ops->lib->rfkill_poll(rt2x00dev);
-       old_state = !!test_bit(RFKILL_STATE_BLOCKED, &rt2x00dev->rfkill_state);
-
-       if (old_state != state) {
-               input_report_switch(poll_dev->input, SW_RFKILL_ALL, state);
-               change_bit(RFKILL_STATE_BLOCKED, &rt2x00dev->rfkill_state);
-       }
-}
-
-void rt2x00rfkill_register(struct rt2x00_dev *rt2x00dev)
-{
-       if (!test_bit(RFKILL_STATE_ALLOCATED, &rt2x00dev->rfkill_state) ||
-           test_bit(RFKILL_STATE_REGISTERED, &rt2x00dev->rfkill_state))
-               return;
-
-       if (input_register_polled_device(rt2x00dev->rfkill_poll_dev)) {
-               ERROR(rt2x00dev, "Failed to register polled device.\n");
-               return;
-       }
-
-       __set_bit(RFKILL_STATE_REGISTERED, &rt2x00dev->rfkill_state);
-
-       /*
-        * Force initial poll which will detect the initial device state,
-        * and correctly sends the signal to the input layer about this
-        * state.
-        */
-       rt2x00rfkill_poll(rt2x00dev->rfkill_poll_dev);
-}
-
-void rt2x00rfkill_unregister(struct rt2x00_dev *rt2x00dev)
-{
-       if (!test_bit(RFKILL_STATE_ALLOCATED, &rt2x00dev->rfkill_state) ||
-           !test_bit(RFKILL_STATE_REGISTERED, &rt2x00dev->rfkill_state))
-               return;
-
-       input_unregister_polled_device(rt2x00dev->rfkill_poll_dev);
-
-       __clear_bit(RFKILL_STATE_REGISTERED, &rt2x00dev->rfkill_state);
-}
-
-void rt2x00rfkill_allocate(struct rt2x00_dev *rt2x00dev)
-{
-       struct input_polled_dev *poll_dev;
-
-       if (test_bit(RFKILL_STATE_ALLOCATED, &rt2x00dev->rfkill_state) ||
-           !test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags))
-               return;
-
-       poll_dev = input_allocate_polled_device();
-       if (!poll_dev) {
-               ERROR(rt2x00dev, "Failed to allocate polled device.\n");
-               return;
-       }
-
-       poll_dev->private = rt2x00dev;
-       poll_dev->poll = rt2x00rfkill_poll;
-       poll_dev->poll_interval = RFKILL_POLL_INTERVAL;
-
-       poll_dev->input->name = rt2x00dev->ops->name;
-       poll_dev->input->phys = wiphy_name(rt2x00dev->hw->wiphy);
-       poll_dev->input->id.bustype = BUS_HOST;
-       poll_dev->input->id.vendor = 0x1814;
-       poll_dev->input->id.product = rt2x00dev->chip.rt;
-       poll_dev->input->id.version = rt2x00dev->chip.rev;
-       poll_dev->input->dev.parent = wiphy_dev(rt2x00dev->hw->wiphy);
-       poll_dev->input->evbit[0] = BIT(EV_SW);
-       poll_dev->input->swbit[0] = BIT(SW_RFKILL_ALL);
-
-       rt2x00dev->rfkill_poll_dev = poll_dev;
-
-       __set_bit(RFKILL_STATE_ALLOCATED, &rt2x00dev->rfkill_state);
-}
-
-void rt2x00rfkill_free(struct rt2x00_dev *rt2x00dev)
-{
-       if (!__test_and_clear_bit(RFKILL_STATE_ALLOCATED,
-                                 &rt2x00dev->rfkill_state))
-               return;
-
-       input_free_polled_device(rt2x00dev->rfkill_poll_dev);
-       rt2x00dev->rfkill_poll_dev = NULL;
-}
index 49b29ff..8a49d99 100644 (file)
@@ -237,7 +237,6 @@ static const struct rt2x00debug rt61pci_rt2x00debug = {
 };
 #endif /* CONFIG_RT2X00_LIB_DEBUGFS */
 
-#ifdef CONFIG_RT2X00_LIB_RFKILL
 static int rt61pci_rfkill_poll(struct rt2x00_dev *rt2x00dev)
 {
        u32 reg;
@@ -245,9 +244,6 @@ static int rt61pci_rfkill_poll(struct rt2x00_dev *rt2x00dev)
        rt2x00pci_register_read(rt2x00dev, MAC_CSR13, &reg);
        return rt2x00_get_field32(reg, MAC_CSR13_BIT5);
 }
-#else
-#define rt61pci_rfkill_poll    NULL
-#endif /* CONFIG_RT2X00_LIB_RFKILL */
 
 #ifdef CONFIG_RT2X00_LIB_LEDS
 static void rt61pci_brightness_set(struct led_classdev *led_cdev,
@@ -2338,10 +2334,8 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
        /*
         * Detect if this device has an hardware controlled radio.
         */
-#ifdef CONFIG_RT2X00_LIB_RFKILL
        if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO))
                __set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags);
-#endif /* CONFIG_RT2X00_LIB_RFKILL */
 
        /*
         * Read frequency offset and RF programming sequence.
@@ -2728,6 +2722,7 @@ static const struct ieee80211_ops rt61pci_mac80211_ops = {
        .conf_tx                = rt61pci_conf_tx,
        .get_tx_stats           = rt2x00mac_get_tx_stats,
        .get_tsf                = rt61pci_get_tsf,
+       .rfkill_poll            = rt2x00mac_rfkill_poll,
 };
 
 static const struct rt2x00lib_ops rt61pci_rt2x00_ops = {
index c188488..ad2898c 100644 (file)
@@ -183,7 +183,6 @@ static const struct rt2x00debug rt73usb_rt2x00debug = {
 };
 #endif /* CONFIG_RT2X00_LIB_DEBUGFS */
 
-#ifdef CONFIG_RT2X00_LIB_RFKILL
 static int rt73usb_rfkill_poll(struct rt2x00_dev *rt2x00dev)
 {
        u32 reg;
@@ -191,9 +190,6 @@ static int rt73usb_rfkill_poll(struct rt2x00_dev *rt2x00dev)
        rt2x00usb_register_read(rt2x00dev, MAC_CSR13, &reg);
        return rt2x00_get_field32(reg, MAC_CSR13_BIT7);
 }
-#else
-#define rt73usb_rfkill_poll    NULL
-#endif /* CONFIG_RT2X00_LIB_RFKILL */
 
 #ifdef CONFIG_RT2X00_LIB_LEDS
 static void rt73usb_brightness_set(struct led_classdev *led_cdev,
@@ -1863,10 +1859,8 @@ static int rt73usb_init_eeprom(struct rt2x00_dev *rt2x00dev)
        /*
         * Detect if this device has an hardware controlled radio.
         */
-#ifdef CONFIG_RT2X00_LIB_RFKILL
        if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO))
                __set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags);
-#endif /* CONFIG_RT2X00_LIB_RFKILL */
 
        /*
         * Read frequency offset.
@@ -2253,6 +2247,7 @@ static const struct ieee80211_ops rt73usb_mac80211_ops = {
        .conf_tx                = rt73usb_conf_tx,
        .get_tx_stats           = rt2x00mac_get_tx_stats,
        .get_tsf                = rt73usb_get_tsf,
+       .rfkill_poll            = rt2x00mac_rfkill_poll,
 };
 
 static const struct rt2x00lib_ops rt73usb_rt2x00_ops = {
index 7e65d7c..09f46ab 100644 (file)
@@ -143,7 +143,8 @@ static void rtl8180_handle_rx(struct ieee80211_hw *dev)
                        if (flags & RTL818X_RX_DESC_FLAG_CRC32_ERR)
                                rx_status.flag |= RX_FLAG_FAILED_FCS_CRC;
 
-                       ieee80211_rx_irqsafe(dev, skb, &rx_status);
+                       memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status));
+                       ieee80211_rx_irqsafe(dev, skb);
 
                        skb = new_skb;
                        priv->rx_buf[priv->rx_idx] = skb;
@@ -280,7 +281,7 @@ static int rtl8180_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
                                (ieee80211_get_tx_rate(dev, info)->bitrate * 2) / 10);
                remainder = (16 * (skb->len + 4)) %
                            ((ieee80211_get_tx_rate(dev, info)->bitrate * 2) / 10);
-               if (remainder > 0 && remainder <= 6)
+               if (remainder <= 6)
                        plcp_len |= 1 << 15;
        }
 
index 294250e..c9b9dbe 100644 (file)
@@ -380,7 +380,8 @@ static void rtl8187_rx_cb(struct urb *urb)
        rx_status.flag |= RX_FLAG_TSFT;
        if (flags & RTL818X_RX_DESC_FLAG_CRC32_ERR)
                rx_status.flag |= RX_FLAG_FAILED_FCS_CRC;
-       ieee80211_rx_irqsafe(dev, skb, &rx_status);
+       memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status));
+       ieee80211_rx_irqsafe(dev, skb);
 
        skb = dev_alloc_skb(RTL8187_MAX_RX);
        if (unlikely(!skb)) {
index 38366a5..73300c2 100644 (file)
@@ -1582,7 +1582,7 @@ static int strip_xmit(struct sk_buff *skb, struct net_device *dev)
 
        if (skb)
                dev_kfree_skb(skb);
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 /*
index ab7fc5c..5cb5329 100644 (file)
@@ -2891,7 +2891,7 @@ static int wavelan_packet_xmit(struct sk_buff *skb, struct net_device * dev)
 #ifdef DEBUG_TX_TRACE
        printk(KERN_DEBUG "%s: <-wavelan_packet_xmit()\n", dev->name);
 #endif
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 /*********************** HARDWARE CONFIGURATION ***********************/
index 6af7064..9dd241a 100644 (file)
@@ -3113,7 +3113,7 @@ wavelan_packet_xmit(struct sk_buff *      skb,
         * able to detect collisions, therefore in theory we don't really
         * need to pad. Jean II */
        if (skb_padto(skb, ETH_ZLEN))
-               return 0;
+               return NETDEV_TX_OK;
 
   wv_packet_write(dev, skb->data, skb->len);
 
@@ -3122,7 +3122,7 @@ wavelan_packet_xmit(struct sk_buff *      skb,
 #ifdef DEBUG_TX_TRACE
   printk(KERN_DEBUG "%s: <-wavelan_packet_xmit()\n", dev->name);
 #endif
-  return(0);
+  return NETDEV_TX_OK;
 }
 
 /********************** HARDWARE CONFIGURATION **********************/
index a82c4cd..82a0f97 100644 (file)
@@ -1,11 +1,18 @@
-config WL12XX
-       tristate "TI wl1251/wl1271 support"
-       depends on MAC80211 && WLAN_80211 && SPI_MASTER && GENERIC_HARDIRQS && EXPERIMENTAL
+menuconfig WL12XX
+       boolean "TI wl12xx driver support"
+       depends on MAC80211 && WLAN_80211 && EXPERIMENTAL
+       ---help---
+         This will enable TI wl12xx driver support. The drivers make
+         use of the mac80211 stack.
+
+config WL1251
+       tristate "TI wl1251 support"
+       depends on WL12XX && SPI_MASTER && GENERIC_HARDIRQS
        select FW_LOADER
        select CRC7
        ---help---
          This module adds support for wireless adapters based on
-         TI wl1251/wl1271 chipsets.
+         TI wl1251 chipset.
 
-         If you choose to build a module, it'll be called wl12xx. Say N if
+         If you choose to build a module, it'll be called wl1251. Say N if
          unsure.
index d43de27..d5595a8 100644 (file)
@@ -1,4 +1,5 @@
-wl12xx-objs            = main.o spi.o event.o tx.o rx.o \
-                         ps.o cmd.o acx.o boot.o init.o wl1251.o \
-                         debugfs.o
-obj-$(CONFIG_WL12XX)   += wl12xx.o
+wl1251-objs            = wl1251_main.o wl1251_spi.o wl1251_event.o \
+                         wl1251_tx.o wl1251_rx.o wl1251_ps.o wl1251_cmd.o \
+                         wl1251_acx.o wl1251_boot.o wl1251_init.o \
+                         wl1251_ops.o wl1251_debugfs.o
+obj-$(CONFIG_WL1251)   += wl1251.o
diff --git a/drivers/net/wireless/wl12xx/acx.c b/drivers/net/wireless/wl12xx/acx.c
deleted file mode 100644 (file)
index 1cfd458..0000000
+++ /dev/null
@@ -1,689 +0,0 @@
-#include "acx.h"
-
-#include <linux/module.h>
-#include <linux/crc7.h>
-#include <linux/spi/spi.h>
-
-#include "wl12xx.h"
-#include "wl12xx_80211.h"
-#include "reg.h"
-#include "spi.h"
-#include "ps.h"
-
-int wl12xx_acx_frame_rates(struct wl12xx *wl, u8 ctrl_rate, u8 ctrl_mod,
-                          u8 mgt_rate, u8 mgt_mod)
-{
-       int ret;
-       struct acx_fw_gen_frame_rates rates;
-
-       wl12xx_debug(DEBUG_ACX, "acx frame rates");
-
-       rates.header.id = ACX_FW_GEN_FRAME_RATES;
-       rates.header.len = sizeof(struct acx_fw_gen_frame_rates) -
-               sizeof(struct acx_header);
-
-       rates.tx_ctrl_frame_rate = ctrl_rate;
-       rates.tx_ctrl_frame_mod = ctrl_mod;
-       rates.tx_mgt_frame_rate = mgt_rate;
-       rates.tx_mgt_frame_mod = mgt_mod;
-
-       ret = wl12xx_cmd_configure(wl, &rates, sizeof(rates));
-       if (ret < 0) {
-               wl12xx_error("Failed to set FW rates and modulation");
-               return ret;
-       }
-
-       return 0;
-}
-
-
-int wl12xx_acx_station_id(struct wl12xx *wl)
-{
-       int ret, i;
-       struct dot11_station_id mac;
-
-       wl12xx_debug(DEBUG_ACX, "acx dot11_station_id");
-
-       mac.header.id = DOT11_STATION_ID;
-       mac.header.len = sizeof(mac) - sizeof(struct acx_header);
-
-       for (i = 0; i < ETH_ALEN; i++)
-               mac.mac[i] = wl->mac_addr[ETH_ALEN - 1 - i];
-
-       ret = wl12xx_cmd_configure(wl, &mac, sizeof(mac));
-       if (ret < 0)
-               return ret;
-
-       return 0;
-}
-
-int wl12xx_acx_default_key(struct wl12xx *wl, u8 key_id)
-{
-       struct acx_dot11_default_key default_key;
-       int ret;
-
-       wl12xx_debug(DEBUG_ACX, "acx dot11_default_key (%d)", key_id);
-
-       default_key.header.id = DOT11_DEFAULT_KEY;
-       default_key.header.len = sizeof(default_key) -
-               sizeof(struct acx_header);
-
-       default_key.id = key_id;
-
-       ret = wl12xx_cmd_configure(wl, &default_key, sizeof(default_key));
-       if (ret < 0) {
-               wl12xx_error("Couldnt set default key");
-               return ret;
-       }
-
-       wl->default_key = key_id;
-
-       return 0;
-}
-
-int wl12xx_acx_wake_up_conditions(struct wl12xx *wl, u8 listen_interval)
-{
-       struct acx_wake_up_condition wake_up;
-
-       wl12xx_debug(DEBUG_ACX, "acx wake up conditions");
-
-       wake_up.header.id = ACX_WAKE_UP_CONDITIONS;
-       wake_up.header.len = sizeof(wake_up) - sizeof(struct acx_header);
-
-       wake_up.wake_up_event = WAKE_UP_EVENT_DTIM_BITMAP;
-       wake_up.listen_interval = listen_interval;
-
-       return wl12xx_cmd_configure(wl, &wake_up, sizeof(wake_up));
-}
-
-int wl12xx_acx_sleep_auth(struct wl12xx *wl, u8 sleep_auth)
-{
-       int ret;
-       struct acx_sleep_auth auth;
-
-       wl12xx_debug(DEBUG_ACX, "acx sleep auth");
-
-       auth.header.id = ACX_SLEEP_AUTH;
-       auth.header.len = sizeof(auth) - sizeof(struct acx_header);
-
-       auth.sleep_auth = sleep_auth;
-
-       ret = wl12xx_cmd_configure(wl, &auth, sizeof(auth));
-       if (ret < 0)
-               return ret;
-
-       return 0;
-}
-
-int wl12xx_acx_fw_version(struct wl12xx *wl, char *buf, size_t len)
-{
-       struct wl12xx_command cmd;
-       struct acx_revision *rev;
-       int ret;
-
-       wl12xx_debug(DEBUG_ACX, "acx fw rev");
-
-       memset(&cmd, 0, sizeof(cmd));
-
-       ret = wl12xx_cmd_interrogate(wl, ACX_FW_REV, sizeof(*rev), &cmd);
-       if (ret < 0) {
-               wl12xx_warning("ACX_FW_REV interrogate failed");
-               return ret;
-       }
-
-       rev = (struct acx_revision *) &cmd.parameters;
-
-       /* be careful with the buffer sizes */
-       strncpy(buf, rev->fw_version, min(len, sizeof(rev->fw_version)));
-
-       /*
-        * if the firmware version string is exactly
-        * sizeof(rev->fw_version) long or fw_len is less than
-        * sizeof(rev->fw_version) it won't be null terminated
-        */
-       buf[min(len, sizeof(rev->fw_version)) - 1] = '\0';
-
-       return 0;
-}
-
-int wl12xx_acx_tx_power(struct wl12xx *wl, int power)
-{
-       struct acx_current_tx_power ie;
-       int ret;
-
-       wl12xx_debug(DEBUG_ACX, "acx dot11_cur_tx_pwr");
-
-       if (power < 0 || power > 25)
-               return -EINVAL;
-
-       memset(&ie, 0, sizeof(ie));
-
-       ie.header.id = DOT11_CUR_TX_PWR;
-       ie.header.len = sizeof(ie) - sizeof(struct acx_header);
-       ie.current_tx_power = power * 10;
-
-       ret = wl12xx_cmd_configure(wl, &ie, sizeof(ie));
-       if (ret < 0) {
-               wl12xx_warning("configure of tx power failed: %d", ret);
-               return ret;
-       }
-
-       return 0;
-}
-
-int wl12xx_acx_feature_cfg(struct wl12xx *wl)
-{
-       struct acx_feature_config feature;
-       int ret;
-
-       wl12xx_debug(DEBUG_ACX, "acx feature cfg");
-
-       memset(&feature, 0, sizeof(feature));
-
-       feature.header.id = ACX_FEATURE_CFG;
-       feature.header.len = sizeof(feature) - sizeof(struct acx_header);
-
-       /* DF_ENCRYPTION_DISABLE and DF_SNIFF_MODE_ENABLE are disabled */
-       feature.data_flow_options = 0;
-       feature.options = 0;
-
-       ret = wl12xx_cmd_configure(wl, &feature, sizeof(feature));
-       if (ret < 0)
-               wl12xx_error("Couldnt set HW encryption");
-
-       return ret;
-}
-
-int wl12xx_acx_mem_map(struct wl12xx *wl, void *mem_map, size_t len)
-{
-       struct wl12xx_command cmd;
-       int ret;
-
-       wl12xx_debug(DEBUG_ACX, "acx mem map");
-
-       ret = wl12xx_cmd_interrogate(wl, ACX_MEM_MAP, len, &cmd);
-       if (ret < 0)
-               return ret;
-       else if (cmd.status != CMD_STATUS_SUCCESS)
-               return -EIO;
-
-       memcpy(mem_map, &cmd.parameters, len);
-
-       return 0;
-}
-
-int wl12xx_acx_data_path_params(struct wl12xx *wl,
-                               struct acx_data_path_params_resp *data_path)
-{
-       struct acx_data_path_params params;
-       struct wl12xx_command cmd;
-       int ret;
-
-       wl12xx_debug(DEBUG_ACX, "acx data path params");
-
-       params.rx_packet_ring_chunk_size = DP_RX_PACKET_RING_CHUNK_SIZE;
-       params.tx_packet_ring_chunk_size = DP_TX_PACKET_RING_CHUNK_SIZE;
-
-       params.rx_packet_ring_chunk_num = DP_RX_PACKET_RING_CHUNK_NUM;
-       params.tx_packet_ring_chunk_num = DP_TX_PACKET_RING_CHUNK_NUM;
-
-       params.tx_complete_threshold = 1;
-
-       params.tx_complete_ring_depth = FW_TX_CMPLT_BLOCK_SIZE;
-
-       params.tx_complete_timeout = DP_TX_COMPLETE_TIME_OUT;
-
-       params.header.id = ACX_DATA_PATH_PARAMS;
-       params.header.len = sizeof(params) - sizeof(struct acx_header);
-
-       ret = wl12xx_cmd_configure(wl, &params, sizeof(params));
-       if (ret < 0)
-               return ret;
-
-
-       ret = wl12xx_cmd_interrogate(wl, ACX_DATA_PATH_PARAMS,
-                                    sizeof(struct acx_data_path_params_resp),
-                                    &cmd);
-
-       if (ret < 0) {
-               wl12xx_warning("failed to read data path parameters: %d", ret);
-               return ret;
-       } else if (cmd.status != CMD_STATUS_SUCCESS) {
-               wl12xx_warning("data path parameter acx status failed");
-               return -EIO;
-       }
-
-       memcpy(data_path, &cmd.parameters, sizeof(*data_path));
-
-       return 0;
-}
-
-int wl12xx_acx_rx_msdu_life_time(struct wl12xx *wl, u32 life_time)
-{
-       struct rx_msdu_lifetime msdu_lifetime;
-       int ret;
-
-       wl12xx_debug(DEBUG_ACX, "acx rx msdu life time");
-
-       msdu_lifetime.header.id = DOT11_RX_MSDU_LIFE_TIME;
-       msdu_lifetime.header.len = sizeof(msdu_lifetime) -
-               sizeof(struct acx_header);
-       msdu_lifetime.lifetime = life_time;
-
-       ret = wl12xx_cmd_configure(wl, &msdu_lifetime, sizeof(msdu_lifetime));
-       if (ret < 0) {
-               wl12xx_warning("failed to set rx msdu life time: %d", ret);
-               return ret;
-       }
-
-       return 0;
-}
-
-int wl12xx_acx_rx_config(struct wl12xx *wl, u32 config, u32 filter)
-{
-       struct acx_rx_config rx_config;
-       int ret;
-
-       wl12xx_debug(DEBUG_ACX, "acx rx config");
-
-       rx_config.header.id = ACX_RX_CFG;
-       rx_config.header.len = sizeof(rx_config) - sizeof(struct acx_header);
-       rx_config.config_options = config;
-       rx_config.filter_options = filter;
-
-       ret = wl12xx_cmd_configure(wl, &rx_config, sizeof(rx_config));
-       if (ret < 0) {
-               wl12xx_warning("failed to set rx config: %d", ret);
-               return ret;
-       }
-
-       return 0;
-}
-
-int wl12xx_acx_pd_threshold(struct wl12xx *wl)
-{
-       struct acx_packet_detection packet_detection;
-       int ret;
-
-       wl12xx_debug(DEBUG_ACX, "acx data pd threshold");
-
-       /* FIXME: threshold value not set */
-       packet_detection.header.id = ACX_PD_THRESHOLD;
-       packet_detection.header.len = sizeof(packet_detection) -
-               sizeof(struct acx_header);
-
-       ret = wl12xx_cmd_configure(wl, &packet_detection,
-                                  sizeof(packet_detection));
-       if (ret < 0) {
-               wl12xx_warning("failed to set pd threshold: %d", ret);
-               return ret;
-       }
-
-       return 0;
-}
-
-int wl12xx_acx_slot(struct wl12xx *wl, enum acx_slot_type slot_time)
-{
-       struct acx_slot slot;
-       int ret;
-
-       wl12xx_debug(DEBUG_ACX, "acx slot");
-
-       slot.header.id = ACX_SLOT;
-       slot.header.len = sizeof(slot) - sizeof(struct acx_header);
-
-       slot.wone_index = STATION_WONE_INDEX;
-       slot.slot_time = slot_time;
-
-       ret = wl12xx_cmd_configure(wl, &slot, sizeof(slot));
-       if (ret < 0) {
-               wl12xx_warning("failed to set slot time: %d", ret);
-               return ret;
-       }
-
-       return 0;
-}
-
-int wl12xx_acx_group_address_tbl(struct wl12xx *wl)
-{
-       struct multicast_grp_addr_start multicast;
-       int ret;
-
-       wl12xx_debug(DEBUG_ACX, "acx group address tbl");
-
-       /* MAC filtering */
-       multicast.header.id = DOT11_GROUP_ADDRESS_TBL;
-       multicast.header.len = sizeof(multicast) - sizeof(struct acx_header);
-
-       multicast.enabled = 0;
-       multicast.num_groups = 0;
-       memset(multicast.mac_table, 0, ADDRESS_GROUP_MAX_LEN);
-
-       ret = wl12xx_cmd_configure(wl, &multicast, sizeof(multicast));
-       if (ret < 0) {
-               wl12xx_warning("failed to set group addr table: %d", ret);
-               return ret;
-       }
-
-       return 0;
-}
-
-int wl12xx_acx_service_period_timeout(struct wl12xx *wl)
-{
-       struct acx_rx_timeout rx_timeout;
-       int ret;
-
-       wl12xx_debug(DEBUG_ACX, "acx service period timeout");
-
-       /* RX timeout */
-       rx_timeout.header.id = ACX_SERVICE_PERIOD_TIMEOUT;
-       rx_timeout.header.len = sizeof(rx_timeout) - sizeof(struct acx_header);
-
-       rx_timeout.ps_poll_timeout = RX_TIMEOUT_PS_POLL_DEF;
-       rx_timeout.upsd_timeout = RX_TIMEOUT_UPSD_DEF;
-
-       ret = wl12xx_cmd_configure(wl, &rx_timeout, sizeof(rx_timeout));
-       if (ret < 0) {
-               wl12xx_warning("failed to set service period timeout: %d",
-                              ret);
-               return ret;
-       }
-
-       return 0;
-}
-
-int wl12xx_acx_rts_threshold(struct wl12xx *wl, u16 rts_threshold)
-{
-       struct acx_rts_threshold rts;
-       int ret;
-
-       wl12xx_debug(DEBUG_ACX, "acx rts threshold");
-
-       rts.header.id = DOT11_RTS_THRESHOLD;
-       rts.header.len = sizeof(rts) - sizeof(struct acx_header);
-
-       rts.threshold = rts_threshold;
-
-       ret = wl12xx_cmd_configure(wl, &rts, sizeof(rts));
-       if (ret < 0) {
-               wl12xx_warning("failed to set rts threshold: %d", ret);
-               return ret;
-       }
-
-       return 0;
-}
-
-int wl12xx_acx_beacon_filter_opt(struct wl12xx *wl)
-{
-       struct acx_beacon_filter_option beacon_filter;
-       int ret;
-
-       wl12xx_debug(DEBUG_ACX, "acx beacon filter opt");
-
-       beacon_filter.header.id = ACX_BEACON_FILTER_OPT;
-       beacon_filter.header.len = sizeof(beacon_filter) -
-               sizeof(struct acx_header);
-
-       beacon_filter.enable = 0;
-       beacon_filter.max_num_beacons = 0;
-
-       ret = wl12xx_cmd_configure(wl, &beacon_filter, sizeof(beacon_filter));
-       if (ret < 0) {
-               wl12xx_warning("failed to set beacon filter opt: %d", ret);
-               return ret;
-       }
-
-       return 0;
-}
-
-int wl12xx_acx_beacon_filter_table(struct wl12xx *wl)
-{
-       struct acx_beacon_filter_ie_table ie_table;
-       int ret;
-
-       wl12xx_debug(DEBUG_ACX, "acx beacon filter table");
-
-       ie_table.header.id = ACX_BEACON_FILTER_TABLE;
-       ie_table.header.len = sizeof(ie_table) - sizeof(struct acx_header);
-
-       ie_table.num_ie = 0;
-       memset(ie_table.table, 0, BEACON_FILTER_TABLE_MAX_SIZE);
-
-       ret = wl12xx_cmd_configure(wl, &ie_table, sizeof(ie_table));
-       if (ret < 0) {
-               wl12xx_warning("failed to set beacon filter table: %d", ret);
-               return ret;
-       }
-
-       return 0;
-}
-
-int wl12xx_acx_sg_enable(struct wl12xx *wl)
-{
-       struct acx_bt_wlan_coex pta;
-       int ret;
-
-       wl12xx_debug(DEBUG_ACX, "acx sg enable");
-
-       pta.header.id = ACX_SG_ENABLE;
-       pta.header.len = sizeof(pta) - sizeof(struct acx_header);
-
-       pta.enable = SG_ENABLE;
-
-       ret = wl12xx_cmd_configure(wl, &pta, sizeof(pta));
-       if (ret < 0) {
-               wl12xx_warning("failed to set softgemini enable: %d", ret);
-               return ret;
-       }
-
-       return 0;
-}
-
-int wl12xx_acx_sg_cfg(struct wl12xx *wl)
-{
-       struct acx_bt_wlan_coex_param param;
-       int ret;
-
-       wl12xx_debug(DEBUG_ACX, "acx sg cfg");
-
-       /* BT-WLAN coext parameters */
-       param.header.id = ACX_SG_CFG;
-       param.header.len = sizeof(param) - sizeof(struct acx_header);
-
-       param.min_rate = RATE_INDEX_24MBPS;
-       param.bt_hp_max_time = PTA_BT_HP_MAXTIME_DEF;
-       param.wlan_hp_max_time = PTA_WLAN_HP_MAX_TIME_DEF;
-       param.sense_disable_timer = PTA_SENSE_DISABLE_TIMER_DEF;
-       param.rx_time_bt_hp = PTA_PROTECTIVE_RX_TIME_DEF;
-       param.tx_time_bt_hp = PTA_PROTECTIVE_TX_TIME_DEF;
-       param.rx_time_bt_hp_fast = PTA_PROTECTIVE_RX_TIME_FAST_DEF;
-       param.tx_time_bt_hp_fast = PTA_PROTECTIVE_TX_TIME_FAST_DEF;
-       param.wlan_cycle_fast = PTA_CYCLE_TIME_FAST_DEF;
-       param.bt_anti_starvation_period = PTA_ANTI_STARVE_PERIOD_DEF;
-       param.next_bt_lp_packet = PTA_TIMEOUT_NEXT_BT_LP_PACKET_DEF;
-       param.wake_up_beacon = PTA_TIME_BEFORE_BEACON_DEF;
-       param.hp_dm_max_guard_time = PTA_HPDM_MAX_TIME_DEF;
-       param.next_wlan_packet = PTA_TIME_OUT_NEXT_WLAN_DEF;
-       param.antenna_type = PTA_ANTENNA_TYPE_DEF;
-       param.signal_type = PTA_SIGNALING_TYPE_DEF;
-       param.afh_leverage_on = PTA_AFH_LEVERAGE_ON_DEF;
-       param.quiet_cycle_num = PTA_NUMBER_QUIET_CYCLE_DEF;
-       param.max_cts = PTA_MAX_NUM_CTS_DEF;
-       param.wlan_packets_num = PTA_NUMBER_OF_WLAN_PACKETS_DEF;
-       param.bt_packets_num = PTA_NUMBER_OF_BT_PACKETS_DEF;
-       param.missed_rx_avalanche = PTA_RX_FOR_AVALANCHE_DEF;
-       param.wlan_elp_hp = PTA_ELP_HP_DEF;
-       param.bt_anti_starvation_cycles = PTA_ANTI_STARVE_NUM_CYCLE_DEF;
-       param.ack_mode_dual_ant = PTA_ACK_MODE_DEF;
-       param.pa_sd_enable = PTA_ALLOW_PA_SD_DEF;
-       param.pta_auto_mode_enable = PTA_AUTO_MODE_NO_CTS_DEF;
-       param.bt_hp_respected_num = PTA_BT_HP_RESPECTED_DEF;
-
-       ret = wl12xx_cmd_configure(wl, &param, sizeof(param));
-       if (ret < 0) {
-               wl12xx_warning("failed to set sg config: %d", ret);
-               return ret;
-       }
-
-       return 0;
-}
-
-int wl12xx_acx_cca_threshold(struct wl12xx *wl)
-{
-       struct acx_energy_detection detection;
-       int ret;
-
-       wl12xx_debug(DEBUG_ACX, "acx cca threshold");
-
-       detection.header.id = ACX_CCA_THRESHOLD;
-       detection.header.len = sizeof(detection) - sizeof(struct acx_header);
-
-       detection.rx_cca_threshold = CCA_THRSH_DISABLE_ENERGY_D;
-       detection.tx_energy_detection = 0;
-
-       ret = wl12xx_cmd_configure(wl, &detection, sizeof(detection));
-       if (ret < 0) {
-               wl12xx_warning("failed to set cca threshold: %d", ret);
-               return ret;
-       }
-
-       return 0;
-}
-
-int wl12xx_acx_bcn_dtim_options(struct wl12xx *wl)
-{
-       struct acx_beacon_broadcast bb;
-       int ret;
-
-       wl12xx_debug(DEBUG_ACX, "acx bcn dtim options");
-
-       bb.header.id = ACX_BCN_DTIM_OPTIONS;
-       bb.header.len = sizeof(bb) - sizeof(struct acx_header);
-
-       bb.beacon_rx_timeout = BCN_RX_TIMEOUT_DEF_VALUE;
-       bb.broadcast_timeout = BROADCAST_RX_TIMEOUT_DEF_VALUE;
-       bb.rx_broadcast_in_ps = RX_BROADCAST_IN_PS_DEF_VALUE;
-       bb.ps_poll_threshold = CONSECUTIVE_PS_POLL_FAILURE_DEF;
-
-       ret = wl12xx_cmd_configure(wl, &bb, sizeof(bb));
-       if (ret < 0) {
-               wl12xx_warning("failed to set rx config: %d", ret);
-               return ret;
-       }
-
-       return 0;
-}
-
-int wl12xx_acx_aid(struct wl12xx *wl, u16 aid)
-{
-       struct acx_aid acx_aid;
-       int ret;
-
-       wl12xx_debug(DEBUG_ACX, "acx aid");
-
-       acx_aid.header.id = ACX_AID;
-       acx_aid.header.len = sizeof(acx_aid) - sizeof(struct acx_header);
-
-       acx_aid.aid = aid;
-
-       ret = wl12xx_cmd_configure(wl, &acx_aid, sizeof(acx_aid));
-       if (ret < 0) {
-               wl12xx_warning("failed to set aid: %d", ret);
-               return ret;
-       }
-
-       return 0;
-}
-
-int wl12xx_acx_event_mbox_mask(struct wl12xx *wl, u32 event_mask)
-{
-       struct acx_event_mask mask;
-       int ret;
-
-       wl12xx_debug(DEBUG_ACX, "acx event mbox mask");
-
-       mask.header.id = ACX_EVENT_MBOX_MASK;
-       mask.header.len = sizeof(mask) - sizeof(struct acx_header);
-
-       /* high event mask is unused */
-       mask.high_event_mask = 0xffffffff;
-
-       mask.event_mask = event_mask;
-
-       ret = wl12xx_cmd_configure(wl, &mask, sizeof(mask));
-       if (ret < 0) {
-               wl12xx_warning("failed to set aid: %d", ret);
-               return ret;
-       }
-
-       return 0;
-}
-
-int wl12xx_acx_set_preamble(struct wl12xx *wl, enum acx_preamble_type preamble)
-{
-       struct acx_preamble ie;
-       int ret;
-
-       wl12xx_debug(DEBUG_ACX, "acx_set_preamble");
-
-       memset(&ie, 0, sizeof(ie));
-
-       ie.header.id = ACX_PREAMBLE_TYPE;
-       ie.header.len = sizeof(ie) - sizeof(struct acx_header);
-       ie.preamble = preamble;
-       ret = wl12xx_cmd_configure(wl, &ie, sizeof(ie));
-       if (ret < 0) {
-               wl12xx_warning("Setting of preamble failed: %d", ret);
-               return ret;
-       }
-       return 0;
-}
-
-int wl12xx_acx_cts_protect(struct wl12xx *wl,
-                          enum acx_ctsprotect_type ctsprotect)
-{
-       struct acx_ctsprotect ie;
-       int ret;
-
-       wl12xx_debug(DEBUG_ACX, "acx_set_ctsprotect");
-
-       memset(&ie, 0, sizeof(ie));
-
-       ie.header.id = ACX_CTS_PROTECTION;
-       ie.header.len = sizeof(ie) - sizeof(struct acx_header);
-       ie.ctsprotect = ctsprotect;
-       ret = wl12xx_cmd_configure(wl, &ie, sizeof(ie));
-       if (ret < 0) {
-               wl12xx_warning("Setting of ctsprotect failed: %d", ret);
-               return ret;
-       }
-       return 0;
-}
-
-int wl12xx_acx_statistics(struct wl12xx *wl, struct acx_statistics *stats)
-{
-       struct wl12xx_command *answer;
-       int ret;
-
-       wl12xx_debug(DEBUG_ACX, "acx statistics");
-
-       answer = kmalloc(sizeof(*answer), GFP_KERNEL);
-       if (!answer) {
-               wl12xx_warning("could not allocate memory for acx statistics");
-               ret = -ENOMEM;
-               goto out;
-       }
-
-       ret = wl12xx_cmd_interrogate(wl, ACX_STATISTICS, sizeof(*answer),
-                                    answer);
-       if (ret < 0) {
-               wl12xx_warning("acx statistics failed: %d", ret);
-               goto out;
-       }
-
-       memcpy(stats, answer->parameters, sizeof(*stats));
-
-out:
-       kfree(answer);
-       return ret;
-}
diff --git a/drivers/net/wireless/wl12xx/cmd.c b/drivers/net/wireless/wl12xx/cmd.c
deleted file mode 100644 (file)
index f73ab60..0000000
+++ /dev/null
@@ -1,353 +0,0 @@
-#include "cmd.h"
-
-#include <linux/module.h>
-#include <linux/crc7.h>
-#include <linux/spi/spi.h>
-
-#include "wl12xx.h"
-#include "wl12xx_80211.h"
-#include "reg.h"
-#include "spi.h"
-#include "ps.h"
-
-int wl12xx_cmd_send(struct wl12xx *wl, u16 type, void *buf, size_t buf_len)
-{
-       struct wl12xx_command cmd;
-       unsigned long timeout;
-       size_t cmd_len;
-       u32 intr;
-       int ret = 0;
-
-       memset(&cmd, 0, sizeof(cmd));
-       cmd.id = type;
-       cmd.status = 0;
-       memcpy(cmd.parameters, buf, buf_len);
-       cmd_len = ALIGN(buf_len, 4) + CMDMBOX_HEADER_LEN;
-
-       wl12xx_ps_elp_wakeup(wl);
-
-       wl12xx_spi_mem_write(wl, wl->cmd_box_addr, &cmd, cmd_len);
-
-       wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_CMD);
-
-       timeout = jiffies + msecs_to_jiffies(WL12XX_COMMAND_TIMEOUT);
-
-       intr = wl12xx_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR);
-       while (!(intr & wl->chip.intr_cmd_complete)) {
-               if (time_after(jiffies, timeout)) {
-                       wl12xx_error("command complete timeout");
-                       ret = -ETIMEDOUT;
-                       goto out;
-               }
-
-               msleep(1);
-
-               intr = wl12xx_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR);
-       }
-
-       wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_ACK,
-                          wl->chip.intr_cmd_complete);
-
-out:
-       wl12xx_ps_elp_sleep(wl);
-
-       return ret;
-}
-
-int wl12xx_cmd_test(struct wl12xx *wl, void *buf, size_t buf_len, u8 answer)
-{
-       int ret;
-
-       wl12xx_debug(DEBUG_CMD, "cmd test");
-
-       ret = wl12xx_cmd_send(wl, CMD_TEST, buf, buf_len);
-       if (ret < 0) {
-               wl12xx_warning("TEST command failed");
-               return ret;
-       }
-
-       if (answer) {
-               struct wl12xx_command *cmd_answer;
-
-               /*
-                * The test command got in, we can read the answer.
-                * The answer would be a wl12xx_command, where the
-                * parameter array contains the actual answer.
-                */
-
-               wl12xx_ps_elp_wakeup(wl);
-
-               wl12xx_spi_mem_read(wl, wl->cmd_box_addr, buf, buf_len);
-
-               wl12xx_ps_elp_sleep(wl);
-
-               cmd_answer = buf;
-               if (cmd_answer->status != CMD_STATUS_SUCCESS)
-                       wl12xx_error("TEST command answer error: %d",
-                                    cmd_answer->status);
-       }
-
-       return 0;
-}
-
-
-int wl12xx_cmd_interrogate(struct wl12xx *wl, u16 ie_id, u16 ie_len,
-                          void *answer)
-{
-       struct wl12xx_command *cmd;
-       struct acx_header header;
-       int ret;
-
-       wl12xx_debug(DEBUG_CMD, "cmd interrogate");
-
-       header.id = ie_id;
-       header.len = ie_len - sizeof(header);
-
-       ret = wl12xx_cmd_send(wl, CMD_INTERROGATE, &header, sizeof(header));
-       if (ret < 0) {
-               wl12xx_error("INTERROGATE command failed");
-               return ret;
-       }
-
-       wl12xx_ps_elp_wakeup(wl);
-
-       /* the interrogate command got in, we can read the answer */
-       wl12xx_spi_mem_read(wl, wl->cmd_box_addr, answer,
-                           CMDMBOX_HEADER_LEN + ie_len);
-
-       wl12xx_ps_elp_sleep(wl);
-
-       cmd = answer;
-       if (cmd->status != CMD_STATUS_SUCCESS)
-               wl12xx_error("INTERROGATE command error: %d",
-                            cmd->status);
-
-       return 0;
-
-}
-
-int wl12xx_cmd_configure(struct wl12xx *wl, void *ie, int ie_len)
-{
-       int ret;
-
-       wl12xx_debug(DEBUG_CMD, "cmd configure");
-
-       ret = wl12xx_cmd_send(wl, CMD_CONFIGURE, ie,
-                             ie_len);
-       if (ret < 0) {
-               wl12xx_warning("CONFIGURE command NOK");
-               return ret;
-       }
-
-       return 0;
-
-}
-
-int wl12xx_cmd_vbm(struct wl12xx *wl, u8 identity,
-                  void *bitmap, u16 bitmap_len, u8 bitmap_control)
-{
-       struct vbm_update_request vbm;
-       int ret;
-
-       wl12xx_debug(DEBUG_CMD, "cmd vbm");
-
-       /* Count and period will be filled by the target */
-       vbm.tim.bitmap_ctrl = bitmap_control;
-       if (bitmap_len > PARTIAL_VBM_MAX) {
-               wl12xx_warning("cmd vbm len is %d B, truncating to %d",
-                              bitmap_len, PARTIAL_VBM_MAX);
-               bitmap_len = PARTIAL_VBM_MAX;
-       }
-       memcpy(vbm.tim.pvb_field, bitmap, bitmap_len);
-       vbm.tim.identity = identity;
-       vbm.tim.length = bitmap_len + 3;
-
-       vbm.len = cpu_to_le16(bitmap_len + 5);
-
-       ret = wl12xx_cmd_send(wl, CMD_VBM, &vbm, sizeof(vbm));
-       if (ret < 0) {
-               wl12xx_error("VBM command failed");
-               return ret;
-       }
-
-       return 0;
-}
-
-int wl12xx_cmd_data_path(struct wl12xx *wl, u8 channel, u8 enable)
-{
-       int ret;
-       u16 cmd_rx, cmd_tx;
-
-       wl12xx_debug(DEBUG_CMD, "cmd data path");
-
-       if (enable) {
-               cmd_rx = CMD_ENABLE_RX;
-               cmd_tx = CMD_ENABLE_TX;
-       } else {
-               cmd_rx = CMD_DISABLE_RX;
-               cmd_tx = CMD_DISABLE_TX;
-       }
-
-       ret = wl12xx_cmd_send(wl, cmd_rx, &channel, sizeof(channel));
-       if (ret < 0) {
-               wl12xx_error("rx %s cmd for channel %d failed",
-                            enable ? "start" : "stop", channel);
-               return ret;
-       }
-
-       wl12xx_debug(DEBUG_BOOT, "rx %s cmd channel %d",
-                    enable ? "start" : "stop", channel);
-
-       ret = wl12xx_cmd_send(wl, cmd_tx, &channel, sizeof(channel));
-       if (ret < 0) {
-               wl12xx_error("tx %s cmd for channel %d failed",
-                            enable ? "start" : "stop", channel);
-               return ret;
-       }
-
-       wl12xx_debug(DEBUG_BOOT, "tx %s cmd channel %d",
-                    enable ? "start" : "stop", channel);
-
-       return 0;
-}
-
-int wl12xx_cmd_join(struct wl12xx *wl, u8 bss_type, u8 dtim_interval,
-                   u16 beacon_interval, u8 wait)
-{
-       unsigned long timeout;
-       struct cmd_join join = {};
-       int ret, i;
-       u8 *bssid;
-
-       /* FIXME: this should be in main.c */
-       ret = wl12xx_acx_frame_rates(wl, DEFAULT_HW_GEN_TX_RATE,
-                                    DEFAULT_HW_GEN_MODULATION_TYPE,
-                                    wl->tx_mgmt_frm_rate,
-                                    wl->tx_mgmt_frm_mod);
-       if (ret < 0)
-               return ret;
-
-       wl12xx_debug(DEBUG_CMD, "cmd join");
-
-       /* Reverse order BSSID */
-       bssid = (u8 *)&join.bssid_lsb;
-       for (i = 0; i < ETH_ALEN; i++)
-               bssid[i] = wl->bssid[ETH_ALEN - i - 1];
-
-       join.rx_config_options = wl->rx_config;
-       join.rx_filter_options = wl->rx_filter;
-
-       join.basic_rate_set = RATE_MASK_1MBPS | RATE_MASK_2MBPS |
-               RATE_MASK_5_5MBPS | RATE_MASK_11MBPS;
-
-       join.beacon_interval = beacon_interval;
-       join.dtim_interval = dtim_interval;
-       join.bss_type = bss_type;
-       join.channel = wl->channel;
-       join.ctrl = JOIN_CMD_CTRL_TX_FLUSH;
-
-       ret = wl12xx_cmd_send(wl, CMD_START_JOIN, &join, sizeof(join));
-       if (ret < 0) {
-               wl12xx_error("failed to initiate cmd join");
-               return ret;
-       }
-
-       timeout = msecs_to_jiffies(JOIN_TIMEOUT);
-
-       /*
-        * ugly hack: we should wait for JOIN_EVENT_COMPLETE_ID but to
-        * simplify locking we just sleep instead, for now
-        */
-       if (wait)
-               msleep(10);
-
-       return 0;
-}
-
-int wl12xx_cmd_ps_mode(struct wl12xx *wl, u8 ps_mode)
-{
-       int ret;
-       struct acx_ps_params ps_params;
-
-       /* FIXME: this should be in ps.c */
-       ret = wl12xx_acx_wake_up_conditions(wl, wl->listen_int);
-       if (ret < 0) {
-               wl12xx_error("Couldnt set wake up conditions");
-               return ret;
-       }
-
-       wl12xx_debug(DEBUG_CMD, "cmd set ps mode");
-
-       ps_params.ps_mode = ps_mode;
-       ps_params.send_null_data = 1;
-       ps_params.retries = 5;
-       ps_params.hang_over_period = 128;
-       ps_params.null_data_rate = 1; /* 1 Mbps */
-
-       ret = wl12xx_cmd_send(wl, CMD_SET_PS_MODE, &ps_params,
-                             sizeof(ps_params));
-       if (ret < 0) {
-               wl12xx_error("cmd set_ps_mode failed");
-               return ret;
-       }
-
-       return 0;
-}
-
-int wl12xx_cmd_read_memory(struct wl12xx *wl, u32 addr, u32 len, void *answer)
-{
-       struct cmd_read_write_memory mem_cmd, *mem_answer;
-       struct wl12xx_command cmd;
-       int ret;
-
-       wl12xx_debug(DEBUG_CMD, "cmd read memory");
-
-       memset(&mem_cmd, 0, sizeof(mem_cmd));
-       mem_cmd.addr = addr;
-       mem_cmd.size = len;
-
-       ret = wl12xx_cmd_send(wl, CMD_READ_MEMORY, &mem_cmd, sizeof(mem_cmd));
-       if (ret < 0) {
-               wl12xx_error("read memory command failed: %d", ret);
-               return ret;
-       }
-
-       /* the read command got in, we can now read the answer */
-       wl12xx_spi_mem_read(wl, wl->cmd_box_addr, &cmd,
-                           CMDMBOX_HEADER_LEN + sizeof(mem_cmd));
-
-       if (cmd.status != CMD_STATUS_SUCCESS)
-               wl12xx_error("error in read command result: %d", cmd.status);
-
-       mem_answer = (struct cmd_read_write_memory *) cmd.parameters;
-       memcpy(answer, mem_answer->value, len);
-
-       return 0;
-}
-
-int wl12xx_cmd_template_set(struct wl12xx *wl, u16 cmd_id,
-                           void *buf, size_t buf_len)
-{
-       struct wl12xx_cmd_packet_template template;
-       int ret;
-
-       wl12xx_debug(DEBUG_CMD, "cmd template %d", cmd_id);
-
-       memset(&template, 0, sizeof(template));
-
-       WARN_ON(buf_len > WL12XX_MAX_TEMPLATE_SIZE);
-       buf_len = min_t(size_t, buf_len, WL12XX_MAX_TEMPLATE_SIZE);
-       template.size = cpu_to_le16(buf_len);
-
-       if (buf)
-               memcpy(template.template, buf, buf_len);
-
-       ret = wl12xx_cmd_send(wl, cmd_id, &template,
-                             sizeof(template.size) + buf_len);
-       if (ret < 0) {
-               wl12xx_warning("cmd set_template failed: %d", ret);
-               return ret;
-       }
-
-       return 0;
-}
index e421643..2de47cc 100644 (file)
@@ -26,7 +26,6 @@
 #define __REG_H__
 
 #include <linux/bitops.h>
-#include "wl12xx.h"
 
 #define REGISTERS_BASE 0x00300000
 #define DRPW_BASE      0x00310000
index 1f4a443..665aca0 100644 (file)
@@ -1,7 +1,8 @@
 /*
- * This file is part of wl12xx
+ * This file is part of wl1251
  *
- * Copyright (C) 2008 Nokia Corporation
+ * Copyright (c) 1998-2007 Texas Instruments Incorporated
+ * Copyright (C) 2008-2009 Nokia Corporation
  *
  * Contact: Kalle Valo <kalle.valo@nokia.com>
  *
 #ifndef __WL1251_H__
 #define __WL1251_H__
 
+#include <linux/mutex.h>
+#include <linux/list.h>
 #include <linux/bitops.h>
-
-#include "wl12xx.h"
-#include "acx.h"
-
-#define WL1251_FW_NAME "wl1251-fw.bin"
-#define WL1251_NVS_NAME "wl1251-nvs.bin"
-
-#define WL1251_POWER_ON_SLEEP 10 /* in miliseconds */
-
-void wl1251_setup(struct wl12xx *wl);
-
-
-struct wl1251_acx_memory {
-       __le16 num_stations; /* number of STAs to be supported. */
-       u16 reserved_1;
+#include <net/mac80211.h>
+
+#define DRIVER_NAME "wl1251"
+#define DRIVER_PREFIX DRIVER_NAME ": "
+
+enum {
+       DEBUG_NONE      = 0,
+       DEBUG_IRQ       = BIT(0),
+       DEBUG_SPI       = BIT(1),
+       DEBUG_BOOT      = BIT(2),
+       DEBUG_MAILBOX   = BIT(3),
+       DEBUG_NETLINK   = BIT(4),
+       DEBUG_EVENT     = BIT(5),
+       DEBUG_TX        = BIT(6),
+       DEBUG_RX        = BIT(7),
+       DEBUG_SCAN      = BIT(8),
+       DEBUG_CRYPT     = BIT(9),
+       DEBUG_PSM       = BIT(10),
+       DEBUG_MAC80211  = BIT(11),
+       DEBUG_CMD       = BIT(12),
+       DEBUG_ACX       = BIT(13),
+       DEBUG_ALL       = ~0,
+};
+
+#define DEBUG_LEVEL (DEBUG_NONE)
+
+#define DEBUG_DUMP_LIMIT 1024
+
+#define wl1251_error(fmt, arg...) \
+       printk(KERN_ERR DRIVER_PREFIX "ERROR " fmt "\n", ##arg)
+
+#define wl1251_warning(fmt, arg...) \
+       printk(KERN_WARNING DRIVER_PREFIX "WARNING " fmt "\n", ##arg)
+
+#define wl1251_notice(fmt, arg...) \
+       printk(KERN_INFO DRIVER_PREFIX fmt "\n", ##arg)
+
+#define wl1251_info(fmt, arg...) \
+       printk(KERN_DEBUG DRIVER_PREFIX fmt "\n", ##arg)
+
+#define wl1251_debug(level, fmt, arg...) \
+       do { \
+               if (level & DEBUG_LEVEL) \
+                       printk(KERN_DEBUG DRIVER_PREFIX fmt "\n", ##arg); \
+       } while (0)
+
+#define wl1251_dump(level, prefix, buf, len)   \
+       do { \
+               if (level & DEBUG_LEVEL) \
+                       print_hex_dump(KERN_DEBUG, DRIVER_PREFIX prefix, \
+                                      DUMP_PREFIX_OFFSET, 16, 1,       \
+                                      buf,                             \
+                                      min_t(size_t, len, DEBUG_DUMP_LIMIT), \
+                                      0);                              \
+       } while (0)
+
+#define wl1251_dump_ascii(level, prefix, buf, len)     \
+       do { \
+               if (level & DEBUG_LEVEL) \
+                       print_hex_dump(KERN_DEBUG, DRIVER_PREFIX prefix, \
+                                      DUMP_PREFIX_OFFSET, 16, 1,       \
+                                      buf,                             \
+                                      min_t(size_t, len, DEBUG_DUMP_LIMIT), \
+                                      true);                           \
+       } while (0)
+
+#define WL1251_DEFAULT_RX_CONFIG (CFG_UNI_FILTER_EN |  \
+                                 CFG_BSSID_FILTER_EN)
+
+#define WL1251_DEFAULT_RX_FILTER (CFG_RX_PRSP_EN |  \
+                                 CFG_RX_MGMT_EN |  \
+                                 CFG_RX_DATA_EN |  \
+                                 CFG_RX_CTL_EN |   \
+                                 CFG_RX_BCN_EN |   \
+                                 CFG_RX_AUTH_EN |  \
+                                 CFG_RX_ASSOC_EN)
+
+#define WL1251_BUSY_WORD_LEN 8
+
+struct boot_attr {
+       u32 radio_type;
+       u8 mac_clock;
+       u8 arm_clock;
+       int firmware_debug;
+       u32 minor;
+       u32 major;
+       u32 bugfix;
+};
+
+enum wl1251_state {
+       WL1251_STATE_OFF,
+       WL1251_STATE_ON,
+       WL1251_STATE_PLT,
+};
+
+enum wl1251_partition_type {
+       PART_DOWN,
+       PART_WORK,
+       PART_DRPW,
+
+       PART_TABLE_LEN
+};
+
+struct wl1251_partition {
+       u32 size;
+       u32 start;
+};
+
+struct wl1251_partition_set {
+       struct wl1251_partition mem;
+       struct wl1251_partition reg;
+};
+
+struct wl1251;
+
+/* FIXME: I'm not sure about this structure name */
+struct wl1251_chip {
+       u32 id;
+
+       const char *fw_filename;
+       const char *nvs_filename;
+
+       char fw_ver[21];
+
+       unsigned int power_on_sleep;
+       int intr_cmd_complete;
+       int intr_init_complete;
+
+       int (*op_upload_fw)(struct wl1251 *wl);
+       int (*op_upload_nvs)(struct wl1251 *wl);
+       int (*op_boot)(struct wl1251 *wl);
+       void (*op_set_ecpu_ctrl)(struct wl1251 *wl, u32 flag);
+       void (*op_target_enable_interrupts)(struct wl1251 *wl);
+       int (*op_hw_init)(struct wl1251 *wl);
+       int (*op_plt_init)(struct wl1251 *wl);
+       void (*op_tx_flush)(struct wl1251 *wl);
+       void (*op_fw_version)(struct wl1251 *wl);
+       int (*op_cmd_join)(struct wl1251 *wl, u8 bss_type, u8 dtim_interval,
+                           u16 beacon_interval, u8 wait);
+
+       struct wl1251_partition_set *p_table;
+       enum wl12xx_acx_int_reg *acx_reg_table;
+};
+
+struct wl1251_stats {
+       struct acx_statistics *fw_stats;
+       unsigned long fw_stats_update;
+
+       unsigned int retry_count;
+       unsigned int excessive_retries;
+};
+
+struct wl1251_debugfs {
+       struct dentry *rootdir;
+       struct dentry *fw_statistics;
+
+       struct dentry *tx_internal_desc_overflow;
+
+       struct dentry *rx_out_of_mem;
+       struct dentry *rx_hdr_overflow;
+       struct dentry *rx_hw_stuck;
+       struct dentry *rx_dropped;
+       struct dentry *rx_fcs_err;
+       struct dentry *rx_xfr_hint_trig;
+       struct dentry *rx_path_reset;
+       struct dentry *rx_reset_counter;
+
+       struct dentry *dma_rx_requested;
+       struct dentry *dma_rx_errors;
+       struct dentry *dma_tx_requested;
+       struct dentry *dma_tx_errors;
+
+       struct dentry *isr_cmd_cmplt;
+       struct dentry *isr_fiqs;
+       struct dentry *isr_rx_headers;
+       struct dentry *isr_rx_mem_overflow;
+       struct dentry *isr_rx_rdys;
+       struct dentry *isr_irqs;
+       struct dentry *isr_tx_procs;
+       struct dentry *isr_decrypt_done;
+       struct dentry *isr_dma0_done;
+       struct dentry *isr_dma1_done;
+       struct dentry *isr_tx_exch_complete;
+       struct dentry *isr_commands;
+       struct dentry *isr_rx_procs;
+       struct dentry *isr_hw_pm_mode_changes;
+       struct dentry *isr_host_acknowledges;
+       struct dentry *isr_pci_pm;
+       struct dentry *isr_wakeups;
+       struct dentry *isr_low_rssi;
+
+       struct dentry *wep_addr_key_count;
+       struct dentry *wep_default_key_count;
+       /* skipping wep.reserved */
+       struct dentry *wep_key_not_found;
+       struct dentry *wep_decrypt_fail;
+       struct dentry *wep_packets;
+       struct dentry *wep_interrupt;
+
+       struct dentry *pwr_ps_enter;
+       struct dentry *pwr_elp_enter;
+       struct dentry *pwr_missing_bcns;
+       struct dentry *pwr_wake_on_host;
+       struct dentry *pwr_wake_on_timer_exp;
+       struct dentry *pwr_tx_with_ps;
+       struct dentry *pwr_tx_without_ps;
+       struct dentry *pwr_rcvd_beacons;
+       struct dentry *pwr_power_save_off;
+       struct dentry *pwr_enable_ps;
+       struct dentry *pwr_disable_ps;
+       struct dentry *pwr_fix_tsf_ps;
+       /* skipping cont_miss_bcns_spread for now */
+       struct dentry *pwr_rcvd_awake_beacons;
+
+       struct dentry *mic_rx_pkts;
+       struct dentry *mic_calc_failure;
+
+       struct dentry *aes_encrypt_fail;
+       struct dentry *aes_decrypt_fail;
+       struct dentry *aes_encrypt_packets;
+       struct dentry *aes_decrypt_packets;
+       struct dentry *aes_encrypt_interrupt;
+       struct dentry *aes_decrypt_interrupt;
+
+       struct dentry *event_heart_beat;
+       struct dentry *event_calibration;
+       struct dentry *event_rx_mismatch;
+       struct dentry *event_rx_mem_empty;
+       struct dentry *event_rx_pool;
+       struct dentry *event_oom_late;
+       struct dentry *event_phy_transmit_error;
+       struct dentry *event_tx_stuck;
+
+       struct dentry *ps_pspoll_timeouts;
+       struct dentry *ps_upsd_timeouts;
+       struct dentry *ps_upsd_max_sptime;
+       struct dentry *ps_upsd_max_apturn;
+       struct dentry *ps_pspoll_max_apturn;
+       struct dentry *ps_pspoll_utilization;
+       struct dentry *ps_upsd_utilization;
+
+       struct dentry *rxpipe_rx_prep_beacon_drop;
+       struct dentry *rxpipe_descr_host_int_trig_rx_data;
+       struct dentry *rxpipe_beacon_buffer_thres_host_int_trig_rx_data;
+       struct dentry *rxpipe_missed_beacon_host_int_trig_rx_data;
+       struct dentry *rxpipe_tx_xfr_host_int_trig_rx_data;
+
+       struct dentry *tx_queue_len;
+
+       struct dentry *retry_count;
+       struct dentry *excessive_retries;
+};
+
+struct wl1251 {
+       struct ieee80211_hw *hw;
+       bool mac80211_registered;
+
+       struct spi_device *spi;
+
+       void (*set_power)(bool enable);
+       int irq;
+
+       enum wl1251_state state;
+       struct mutex mutex;
+
+       int physical_mem_addr;
+       int physical_reg_addr;
+       int virtual_mem_addr;
+       int virtual_reg_addr;
+
+       struct wl1251_chip chip;
+
+       int cmd_box_addr;
+       int event_box_addr;
+       struct boot_attr boot_attr;
+
+       u8 *fw;
+       size_t fw_len;
+       u8 *nvs;
+       size_t nvs_len;
+
+       u8 bssid[ETH_ALEN];
+       u8 mac_addr[ETH_ALEN];
+       u8 bss_type;
+       u8 listen_int;
+       int channel;
+
+       void *target_mem_map;
+       struct acx_data_path_params_resp *data_path;
+
+       /* Number of TX packets transferred to the FW, modulo 16 */
+       u32 data_in_count;
+
+       /* Frames scheduled for transmission, not handled yet */
+       struct sk_buff_head tx_queue;
+       bool tx_queue_stopped;
+
+       struct work_struct tx_work;
+       struct work_struct filter_work;
+
+       /* Pending TX frames */
+       struct sk_buff *tx_frames[16];
 
        /*
-        * Nmber of memory buffers for the RX mem pool.
-        * The actual number may be less if there are
-        * not enough blocks left for the minimum num
-        * of TX ones.
+        * Index pointing to the next TX complete entry
+        * in the cyclic XT complete array we get from
+        * the FW.
         */
-       u8 rx_mem_block_num;
-       u8 reserved_2;
-       u8 num_tx_queues; /* From 1 to 16 */
-       u8 host_if_options; /* HOST_IF* */
-       u8 tx_min_mem_block_num;
-       u8 num_ssid_profiles;
-       __le16 debug_buffer_size;
-} __attribute__ ((packed));
-
-
-#define ACX_RX_DESC_MIN                1
-#define ACX_RX_DESC_MAX                127
-#define ACX_RX_DESC_DEF                32
-struct wl1251_acx_rx_queue_config {
-       u8 num_descs;
-       u8 pad;
-       u8 type;
-       u8 priority;
-       __le32 dma_address;
-} __attribute__ ((packed));
-
-#define ACX_TX_DESC_MIN                1
-#define ACX_TX_DESC_MAX                127
-#define ACX_TX_DESC_DEF                16
-struct wl1251_acx_tx_queue_config {
-    u8 num_descs;
-    u8 pad[2];
-    u8 attributes;
-} __attribute__ ((packed));
-
-#define MAX_TX_QUEUE_CONFIGS 5
-#define MAX_TX_QUEUES 4
-struct wl1251_acx_config_memory {
-       struct acx_header header;
-
-       struct wl1251_acx_memory mem_config;
-       struct wl1251_acx_rx_queue_config rx_queue_config;
-       struct wl1251_acx_tx_queue_config tx_queue_config[MAX_TX_QUEUE_CONFIGS];
-} __attribute__ ((packed));
-
-struct wl1251_acx_mem_map {
-       struct acx_header header;
-
-       void *code_start;
-       void *code_end;
-
-       void *wep_defkey_start;
-       void *wep_defkey_end;
+       u32 next_tx_complete;
 
-       void *sta_table_start;
-       void *sta_table_end;
+       /* FW Rx counter */
+       u32 rx_counter;
 
-       void *packet_template_start;
-       void *packet_template_end;
+       /* Rx frames handled */
+       u32 rx_handled;
 
-       void *queue_memory_start;
-       void *queue_memory_end;
+       /* Current double buffer */
+       u32 rx_current_buffer;
+       u32 rx_last_id;
 
-       void *packet_memory_pool_start;
-       void *packet_memory_pool_end;
+       /* The target interrupt mask */
+       u32 intr_mask;
+       struct work_struct irq_work;
 
-       void *debug_buffer1_start;
-       void *debug_buffer1_end;
+       /* The mbox event mask */
+       u32 event_mask;
 
-       void *debug_buffer2_start;
-       void *debug_buffer2_end;
+       /* Mailbox pointers */
+       u32 mbox_ptr[2];
 
-       /* Number of blocks FW allocated for TX packets */
-       u32 num_tx_mem_blocks;
+       /* Are we currently scanning */
+       bool scanning;
 
-       /* Number of blocks FW allocated for RX packets */
-       u32 num_rx_mem_blocks;
-} __attribute__ ((packed));
+       /* Our association ID */
+       u16 aid;
 
-/*************************************************************************
+       /* Default key (for WEP) */
+       u32 default_key;
 
-    Host Interrupt Register (WiLink -> Host)
+       unsigned int tx_mgmt_frm_rate;
+       unsigned int tx_mgmt_frm_mod;
 
-**************************************************************************/
+       unsigned int rx_config;
+       unsigned int rx_filter;
 
-/* RX packet is ready in Xfer buffer #0 */
-#define WL1251_ACX_INTR_RX0_DATA      BIT(0)
+       /* is firmware in elp mode */
+       bool elp;
 
-/* TX result(s) are in the TX complete buffer */
-#define WL1251_ACX_INTR_TX_RESULT      BIT(1)
+       /* we can be in psm, but not in elp, we have to differentiate */
+       bool psm;
 
-/* OBSOLETE */
-#define WL1251_ACX_INTR_TX_XFR         BIT(2)
+       /* PSM mode requested */
+       bool psm_requested;
 
-/* RX packet is ready in Xfer buffer #1 */
-#define WL1251_ACX_INTR_RX1_DATA       BIT(3)
+       /* in dBm */
+       int power_level;
 
-/* Event was entered to Event MBOX #A */
-#define WL1251_ACX_INTR_EVENT_A                BIT(4)
+       struct wl1251_stats stats;
+       struct wl1251_debugfs debugfs;
 
-/* Event was entered to Event MBOX #B */
-#define WL1251_ACX_INTR_EVENT_B                BIT(5)
+       u32 buffer_32;
+       u32 buffer_cmd;
+       u8 buffer_busyword[WL1251_BUSY_WORD_LEN];
+       struct wl1251_rx_descriptor *rx_descriptor;
+};
 
-/* OBSOLETE */
-#define WL1251_ACX_INTR_WAKE_ON_HOST   BIT(6)
+int wl1251_plt_start(struct wl1251 *wl);
+int wl1251_plt_stop(struct wl1251 *wl);
 
-/* Trace meassge on MBOX #A */
-#define WL1251_ACX_INTR_TRACE_A                BIT(7)
+#define DEFAULT_HW_GEN_MODULATION_TYPE    CCK_LONG /* Long Preamble */
+#define DEFAULT_HW_GEN_TX_RATE          RATE_2MBPS
+#define JOIN_TIMEOUT 5000 /* 5000 milliseconds to join */
 
-/* Trace meassge on MBOX #B */
-#define WL1251_ACX_INTR_TRACE_B                BIT(8)
+#define WL1251_DEFAULT_POWER_LEVEL 20
 
-/* Command processing completion */
-#define WL1251_ACX_INTR_CMD_COMPLETE   BIT(9)
+#define WL1251_TX_QUEUE_MAX_LENGTH 20
 
-/* Init sequence is done */
-#define WL1251_ACX_INTR_INIT_COMPLETE  BIT(14)
+/* Different chips need different sleep times after power on.  WL1271 needs
+ * 200ms, WL1251 needs only 10ms.  By default we use 200ms, but as soon as we
+ * know the chip ID, we change the sleep value in the wl1251 chip structure,
+ * so in subsequent power ons, we don't waste more time then needed.  */
+#define WL1251_DEFAULT_POWER_ON_SLEEP 200
 
-#define WL1251_ACX_INTR_ALL           0xFFFFFFFF
+#define CHIP_ID_1251_PG10                 (0x7010101)
+#define CHIP_ID_1251_PG11                 (0x7020101)
+#define CHIP_ID_1251_PG12                 (0x7030101)
+#define CHIP_ID_1271_PG10                 (0x4030101)
+#define CHIP_ID_1271_PG20                 (0x4030111)
 
 #endif
diff --git a/drivers/net/wireless/wl12xx/wl1251_acx.c b/drivers/net/wireless/wl12xx/wl1251_acx.c
new file mode 100644 (file)
index 0000000..5a8d21c
--- /dev/null
@@ -0,0 +1,840 @@
+#include "wl1251_acx.h"
+
+#include <linux/module.h>
+#include <linux/crc7.h>
+#include <linux/spi/spi.h>
+
+#include "wl1251.h"
+#include "reg.h"
+#include "wl1251_spi.h"
+#include "wl1251_ps.h"
+
+int wl1251_acx_frame_rates(struct wl1251 *wl, u8 ctrl_rate, u8 ctrl_mod,
+                          u8 mgt_rate, u8 mgt_mod)
+{
+       struct acx_fw_gen_frame_rates *rates;
+       int ret;
+
+       wl1251_debug(DEBUG_ACX, "acx frame rates");
+
+       rates = kzalloc(sizeof(*rates), GFP_KERNEL);
+       if (!rates) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       rates->tx_ctrl_frame_rate = ctrl_rate;
+       rates->tx_ctrl_frame_mod = ctrl_mod;
+       rates->tx_mgt_frame_rate = mgt_rate;
+       rates->tx_mgt_frame_mod = mgt_mod;
+
+       ret = wl1251_cmd_configure(wl, ACX_FW_GEN_FRAME_RATES,
+                                  rates, sizeof(*rates));
+       if (ret < 0) {
+               wl1251_error("Failed to set FW rates and modulation");
+               goto out;
+       }
+
+out:
+       kfree(rates);
+       return ret;
+}
+
+
+int wl1251_acx_station_id(struct wl1251 *wl)
+{
+       struct acx_dot11_station_id *mac;
+       int ret, i;
+
+       wl1251_debug(DEBUG_ACX, "acx dot11_station_id");
+
+       mac = kzalloc(sizeof(*mac), GFP_KERNEL);
+       if (!mac) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       for (i = 0; i < ETH_ALEN; i++)
+               mac->mac[i] = wl->mac_addr[ETH_ALEN - 1 - i];
+
+       ret = wl1251_cmd_configure(wl, DOT11_STATION_ID, mac, sizeof(*mac));
+       if (ret < 0)
+               goto out;
+
+out:
+       kfree(mac);
+       return ret;
+}
+
+int wl1251_acx_default_key(struct wl1251 *wl, u8 key_id)
+{
+       struct acx_dot11_default_key *default_key;
+       int ret;
+
+       wl1251_debug(DEBUG_ACX, "acx dot11_default_key (%d)", key_id);
+
+       default_key = kzalloc(sizeof(*default_key), GFP_KERNEL);
+       if (!default_key) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       default_key->id = key_id;
+
+       ret = wl1251_cmd_configure(wl, DOT11_DEFAULT_KEY,
+                                  default_key, sizeof(*default_key));
+       if (ret < 0) {
+               wl1251_error("Couldnt set default key");
+               goto out;
+       }
+
+       wl->default_key = key_id;
+
+out:
+       kfree(default_key);
+       return ret;
+}
+
+int wl1251_acx_wake_up_conditions(struct wl1251 *wl, u8 wake_up_event,
+                                 u8 listen_interval)
+{
+       struct acx_wake_up_condition *wake_up;
+       int ret;
+
+       wl1251_debug(DEBUG_ACX, "acx wake up conditions");
+
+       wake_up = kzalloc(sizeof(*wake_up), GFP_KERNEL);
+       if (!wake_up) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       wake_up->wake_up_event = wake_up_event;
+       wake_up->listen_interval = listen_interval;
+
+       ret = wl1251_cmd_configure(wl, ACX_WAKE_UP_CONDITIONS,
+                                  wake_up, sizeof(*wake_up));
+       if (ret < 0) {
+               wl1251_warning("could not set wake up conditions: %d", ret);
+               goto out;
+       }
+
+out:
+       kfree(wake_up);
+       return ret;
+}
+
+int wl1251_acx_sleep_auth(struct wl1251 *wl, u8 sleep_auth)
+{
+       struct acx_sleep_auth *auth;
+       int ret;
+
+       wl1251_debug(DEBUG_ACX, "acx sleep auth");
+
+       auth = kzalloc(sizeof(*auth), GFP_KERNEL);
+       if (!auth) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       auth->sleep_auth = sleep_auth;
+
+       ret = wl1251_cmd_configure(wl, ACX_SLEEP_AUTH, auth, sizeof(*auth));
+       if (ret < 0)
+               return ret;
+
+out:
+       kfree(auth);
+       return ret;
+}
+
+int wl1251_acx_fw_version(struct wl1251 *wl, char *buf, size_t len)
+{
+       struct acx_revision *rev;
+       int ret;
+
+       wl1251_debug(DEBUG_ACX, "acx fw rev");
+
+       rev = kzalloc(sizeof(*rev), GFP_KERNEL);
+       if (!rev) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       ret = wl1251_cmd_interrogate(wl, ACX_FW_REV, rev, sizeof(*rev));
+       if (ret < 0) {
+               wl1251_warning("ACX_FW_REV interrogate failed");
+               goto out;
+       }
+
+       /* be careful with the buffer sizes */
+       strncpy(buf, rev->fw_version, min(len, sizeof(rev->fw_version)));
+
+       /*
+        * if the firmware version string is exactly
+        * sizeof(rev->fw_version) long or fw_len is less than
+        * sizeof(rev->fw_version) it won't be null terminated
+        */
+       buf[min(len, sizeof(rev->fw_version)) - 1] = '\0';
+
+out:
+       kfree(rev);
+       return ret;
+}
+
+int wl1251_acx_tx_power(struct wl1251 *wl, int power)
+{
+       struct acx_current_tx_power *acx;
+       int ret;
+
+       wl1251_debug(DEBUG_ACX, "acx dot11_cur_tx_pwr");
+
+       if (power < 0 || power > 25)
+               return -EINVAL;
+
+       acx = kzalloc(sizeof(*acx), GFP_KERNEL);
+       if (!acx) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       acx->current_tx_power = power * 10;
+
+       ret = wl1251_cmd_configure(wl, DOT11_CUR_TX_PWR, acx, sizeof(*acx));
+       if (ret < 0) {
+               wl1251_warning("configure of tx power failed: %d", ret);
+               goto out;
+       }
+
+out:
+       kfree(acx);
+       return ret;
+}
+
+int wl1251_acx_feature_cfg(struct wl1251 *wl)
+{
+       struct acx_feature_config *feature;
+       int ret;
+
+       wl1251_debug(DEBUG_ACX, "acx feature cfg");
+
+       feature = kzalloc(sizeof(*feature), GFP_KERNEL);
+       if (!feature) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       /* DF_ENCRYPTION_DISABLE and DF_SNIFF_MODE_ENABLE are disabled */
+       feature->data_flow_options = 0;
+       feature->options = 0;
+
+       ret = wl1251_cmd_configure(wl, ACX_FEATURE_CFG,
+                                  feature, sizeof(*feature));
+       if (ret < 0) {
+               wl1251_error("Couldnt set HW encryption");
+               goto out;
+       }
+
+out:
+       kfree(feature);
+       return ret;
+}
+
+int wl1251_acx_mem_map(struct wl1251 *wl, struct acx_header *mem_map,
+                      size_t len)
+{
+       int ret;
+
+       wl1251_debug(DEBUG_ACX, "acx mem map");
+
+       ret = wl1251_cmd_interrogate(wl, ACX_MEM_MAP, mem_map, len);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+int wl1251_acx_data_path_params(struct wl1251 *wl,
+                               struct acx_data_path_params_resp *resp)
+{
+       struct acx_data_path_params *params;
+       int ret;
+
+       wl1251_debug(DEBUG_ACX, "acx data path params");
+
+       params = kzalloc(sizeof(*params), GFP_KERNEL);
+       if (!params) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       params->rx_packet_ring_chunk_size = DP_RX_PACKET_RING_CHUNK_SIZE;
+       params->tx_packet_ring_chunk_size = DP_TX_PACKET_RING_CHUNK_SIZE;
+
+       params->rx_packet_ring_chunk_num = DP_RX_PACKET_RING_CHUNK_NUM;
+       params->tx_packet_ring_chunk_num = DP_TX_PACKET_RING_CHUNK_NUM;
+
+       params->tx_complete_threshold = 1;
+
+       params->tx_complete_ring_depth = FW_TX_CMPLT_BLOCK_SIZE;
+
+       params->tx_complete_timeout = DP_TX_COMPLETE_TIME_OUT;
+
+       ret = wl1251_cmd_configure(wl, ACX_DATA_PATH_PARAMS,
+                                  params, sizeof(*params));
+       if (ret < 0)
+               goto out;
+
+       /* FIXME: shouldn't this be ACX_DATA_PATH_RESP_PARAMS? */
+       ret = wl1251_cmd_interrogate(wl, ACX_DATA_PATH_PARAMS,
+                                    resp, sizeof(*resp));
+
+       if (ret < 0) {
+               wl1251_warning("failed to read data path parameters: %d", ret);
+               goto out;
+       } else if (resp->header.cmd.status != CMD_STATUS_SUCCESS) {
+               wl1251_warning("data path parameter acx status failed");
+               ret = -EIO;
+               goto out;
+       }
+
+out:
+       kfree(params);
+       return ret;
+}
+
+int wl1251_acx_rx_msdu_life_time(struct wl1251 *wl, u32 life_time)
+{
+       struct acx_rx_msdu_lifetime *acx;
+       int ret;
+
+       wl1251_debug(DEBUG_ACX, "acx rx msdu life time");
+
+       acx = kzalloc(sizeof(*acx), GFP_KERNEL);
+       if (!acx) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       acx->lifetime = life_time;
+       ret = wl1251_cmd_configure(wl, DOT11_RX_MSDU_LIFE_TIME,
+                                  acx, sizeof(*acx));
+       if (ret < 0) {
+               wl1251_warning("failed to set rx msdu life time: %d", ret);
+               goto out;
+       }
+
+out:
+       kfree(acx);
+       return ret;
+}
+
+int wl1251_acx_rx_config(struct wl1251 *wl, u32 config, u32 filter)
+{
+       struct acx_rx_config *rx_config;
+       int ret;
+
+       wl1251_debug(DEBUG_ACX, "acx rx config");
+
+       rx_config = kzalloc(sizeof(*rx_config), GFP_KERNEL);
+       if (!rx_config) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       rx_config->config_options = config;
+       rx_config->filter_options = filter;
+
+       ret = wl1251_cmd_configure(wl, ACX_RX_CFG,
+                                  rx_config, sizeof(*rx_config));
+       if (ret < 0) {
+               wl1251_warning("failed to set rx config: %d", ret);
+               goto out;
+       }
+
+out:
+       kfree(rx_config);
+       return ret;
+}
+
+int wl1251_acx_pd_threshold(struct wl1251 *wl)
+{
+       struct acx_packet_detection *pd;
+       int ret;
+
+       wl1251_debug(DEBUG_ACX, "acx data pd threshold");
+
+       pd = kzalloc(sizeof(*pd), GFP_KERNEL);
+       if (!pd) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       /* FIXME: threshold value not set */
+
+       ret = wl1251_cmd_configure(wl, ACX_PD_THRESHOLD, pd, sizeof(*pd));
+       if (ret < 0) {
+               wl1251_warning("failed to set pd threshold: %d", ret);
+               goto out;
+       }
+
+out:
+       kfree(pd);
+       return 0;
+}
+
+int wl1251_acx_slot(struct wl1251 *wl, enum acx_slot_type slot_time)
+{
+       struct acx_slot *slot;
+       int ret;
+
+       wl1251_debug(DEBUG_ACX, "acx slot");
+
+       slot = kzalloc(sizeof(*slot), GFP_KERNEL);
+       if (!slot) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       slot->wone_index = STATION_WONE_INDEX;
+       slot->slot_time = slot_time;
+
+       ret = wl1251_cmd_configure(wl, ACX_SLOT, slot, sizeof(*slot));
+       if (ret < 0) {
+               wl1251_warning("failed to set slot time: %d", ret);
+               goto out;
+       }
+
+out:
+       kfree(slot);
+       return ret;
+}
+
+int wl1251_acx_group_address_tbl(struct wl1251 *wl)
+{
+       struct acx_dot11_grp_addr_tbl *acx;
+       int ret;
+
+       wl1251_debug(DEBUG_ACX, "acx group address tbl");
+
+       acx = kzalloc(sizeof(*acx), GFP_KERNEL);
+       if (!acx) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       /* MAC filtering */
+       acx->enabled = 0;
+       acx->num_groups = 0;
+       memset(acx->mac_table, 0, ADDRESS_GROUP_MAX_LEN);
+
+       ret = wl1251_cmd_configure(wl, DOT11_GROUP_ADDRESS_TBL,
+                                  acx, sizeof(*acx));
+       if (ret < 0) {
+               wl1251_warning("failed to set group addr table: %d", ret);
+               goto out;
+       }
+
+out:
+       kfree(acx);
+       return ret;
+}
+
+int wl1251_acx_service_period_timeout(struct wl1251 *wl)
+{
+       struct acx_rx_timeout *rx_timeout;
+       int ret;
+
+       rx_timeout = kzalloc(sizeof(*rx_timeout), GFP_KERNEL);
+       if (!rx_timeout) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       wl1251_debug(DEBUG_ACX, "acx service period timeout");
+
+       rx_timeout->ps_poll_timeout = RX_TIMEOUT_PS_POLL_DEF;
+       rx_timeout->upsd_timeout = RX_TIMEOUT_UPSD_DEF;
+
+       ret = wl1251_cmd_configure(wl, ACX_SERVICE_PERIOD_TIMEOUT,
+                                  rx_timeout, sizeof(*rx_timeout));
+       if (ret < 0) {
+               wl1251_warning("failed to set service period timeout: %d",
+                              ret);
+               goto out;
+       }
+
+out:
+       kfree(rx_timeout);
+       return ret;
+}
+
+int wl1251_acx_rts_threshold(struct wl1251 *wl, u16 rts_threshold)
+{
+       struct acx_rts_threshold *rts;
+       int ret;
+
+       wl1251_debug(DEBUG_ACX, "acx rts threshold");
+
+       rts = kzalloc(sizeof(*rts), GFP_KERNEL);
+       if (!rts) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       rts->threshold = rts_threshold;
+
+       ret = wl1251_cmd_configure(wl, DOT11_RTS_THRESHOLD, rts, sizeof(*rts));
+       if (ret < 0) {
+               wl1251_warning("failed to set rts threshold: %d", ret);
+               goto out;
+       }
+
+out:
+       kfree(rts);
+       return ret;
+}
+
+int wl1251_acx_beacon_filter_opt(struct wl1251 *wl)
+{
+       struct acx_beacon_filter_option *beacon_filter;
+       int ret;
+
+       wl1251_debug(DEBUG_ACX, "acx beacon filter opt");
+
+       beacon_filter = kzalloc(sizeof(*beacon_filter), GFP_KERNEL);
+       if (!beacon_filter) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       beacon_filter->enable = 0;
+       beacon_filter->max_num_beacons = 0;
+
+       ret = wl1251_cmd_configure(wl, ACX_BEACON_FILTER_OPT,
+                                  beacon_filter, sizeof(*beacon_filter));
+       if (ret < 0) {
+               wl1251_warning("failed to set beacon filter opt: %d", ret);
+               goto out;
+       }
+
+out:
+       kfree(beacon_filter);
+       return ret;
+}
+
+int wl1251_acx_beacon_filter_table(struct wl1251 *wl)
+{
+       struct acx_beacon_filter_ie_table *ie_table;
+       int ret;
+
+       wl1251_debug(DEBUG_ACX, "acx beacon filter table");
+
+       ie_table = kzalloc(sizeof(*ie_table), GFP_KERNEL);
+       if (!ie_table) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       ie_table->num_ie = 0;
+       memset(ie_table->table, 0, BEACON_FILTER_TABLE_MAX_SIZE);
+
+       ret = wl1251_cmd_configure(wl, ACX_BEACON_FILTER_TABLE,
+                                  ie_table, sizeof(*ie_table));
+       if (ret < 0) {
+               wl1251_warning("failed to set beacon filter table: %d", ret);
+               goto out;
+       }
+
+out:
+       kfree(ie_table);
+       return ret;
+}
+
+int wl1251_acx_sg_enable(struct wl1251 *wl)
+{
+       struct acx_bt_wlan_coex *pta;
+       int ret;
+
+       wl1251_debug(DEBUG_ACX, "acx sg enable");
+
+       pta = kzalloc(sizeof(*pta), GFP_KERNEL);
+       if (!pta) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       pta->enable = SG_ENABLE;
+
+       ret = wl1251_cmd_configure(wl, ACX_SG_ENABLE, pta, sizeof(*pta));
+       if (ret < 0) {
+               wl1251_warning("failed to set softgemini enable: %d", ret);
+               goto out;
+       }
+
+out:
+       kfree(pta);
+       return ret;
+}
+
+int wl1251_acx_sg_cfg(struct wl1251 *wl)
+{
+       struct acx_bt_wlan_coex_param *param;
+       int ret;
+
+       wl1251_debug(DEBUG_ACX, "acx sg cfg");
+
+       param = kzalloc(sizeof(*param), GFP_KERNEL);
+       if (!param) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       /* BT-WLAN coext parameters */
+       param->min_rate = RATE_INDEX_24MBPS;
+       param->bt_hp_max_time = PTA_BT_HP_MAXTIME_DEF;
+       param->wlan_hp_max_time = PTA_WLAN_HP_MAX_TIME_DEF;
+       param->sense_disable_timer = PTA_SENSE_DISABLE_TIMER_DEF;
+       param->rx_time_bt_hp = PTA_PROTECTIVE_RX_TIME_DEF;
+       param->tx_time_bt_hp = PTA_PROTECTIVE_TX_TIME_DEF;
+       param->rx_time_bt_hp_fast = PTA_PROTECTIVE_RX_TIME_FAST_DEF;
+       param->tx_time_bt_hp_fast = PTA_PROTECTIVE_TX_TIME_FAST_DEF;
+       param->wlan_cycle_fast = PTA_CYCLE_TIME_FAST_DEF;
+       param->bt_anti_starvation_period = PTA_ANTI_STARVE_PERIOD_DEF;
+       param->next_bt_lp_packet = PTA_TIMEOUT_NEXT_BT_LP_PACKET_DEF;
+       param->wake_up_beacon = PTA_TIME_BEFORE_BEACON_DEF;
+       param->hp_dm_max_guard_time = PTA_HPDM_MAX_TIME_DEF;
+       param->next_wlan_packet = PTA_TIME_OUT_NEXT_WLAN_DEF;
+       param->antenna_type = PTA_ANTENNA_TYPE_DEF;
+       param->signal_type = PTA_SIGNALING_TYPE_DEF;
+       param->afh_leverage_on = PTA_AFH_LEVERAGE_ON_DEF;
+       param->quiet_cycle_num = PTA_NUMBER_QUIET_CYCLE_DEF;
+       param->max_cts = PTA_MAX_NUM_CTS_DEF;
+       param->wlan_packets_num = PTA_NUMBER_OF_WLAN_PACKETS_DEF;
+       param->bt_packets_num = PTA_NUMBER_OF_BT_PACKETS_DEF;
+       param->missed_rx_avalanche = PTA_RX_FOR_AVALANCHE_DEF;
+       param->wlan_elp_hp = PTA_ELP_HP_DEF;
+       param->bt_anti_starvation_cycles = PTA_ANTI_STARVE_NUM_CYCLE_DEF;
+       param->ack_mode_dual_ant = PTA_ACK_MODE_DEF;
+       param->pa_sd_enable = PTA_ALLOW_PA_SD_DEF;
+       param->pta_auto_mode_enable = PTA_AUTO_MODE_NO_CTS_DEF;
+       param->bt_hp_respected_num = PTA_BT_HP_RESPECTED_DEF;
+
+       ret = wl1251_cmd_configure(wl, ACX_SG_CFG, param, sizeof(*param));
+       if (ret < 0) {
+               wl1251_warning("failed to set sg config: %d", ret);
+               goto out;
+       }
+
+out:
+       kfree(param);
+       return ret;
+}
+
+int wl1251_acx_cca_threshold(struct wl1251 *wl)
+{
+       struct acx_energy_detection *detection;
+       int ret;
+
+       wl1251_debug(DEBUG_ACX, "acx cca threshold");
+
+       detection = kzalloc(sizeof(*detection), GFP_KERNEL);
+       if (!detection) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       detection->rx_cca_threshold = CCA_THRSH_DISABLE_ENERGY_D;
+       detection->tx_energy_detection = 0;
+
+       ret = wl1251_cmd_configure(wl, ACX_CCA_THRESHOLD,
+                                  detection, sizeof(*detection));
+       if (ret < 0) {
+               wl1251_warning("failed to set cca threshold: %d", ret);
+               return ret;
+       }
+
+out:
+       kfree(detection);
+       return ret;
+}
+
+int wl1251_acx_bcn_dtim_options(struct wl1251 *wl)
+{
+       struct acx_beacon_broadcast *bb;
+       int ret;
+
+       wl1251_debug(DEBUG_ACX, "acx bcn dtim options");
+
+       bb = kzalloc(sizeof(*bb), GFP_KERNEL);
+       if (!bb) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       bb->beacon_rx_timeout = BCN_RX_TIMEOUT_DEF_VALUE;
+       bb->broadcast_timeout = BROADCAST_RX_TIMEOUT_DEF_VALUE;
+       bb->rx_broadcast_in_ps = RX_BROADCAST_IN_PS_DEF_VALUE;
+       bb->ps_poll_threshold = CONSECUTIVE_PS_POLL_FAILURE_DEF;
+
+       ret = wl1251_cmd_configure(wl, ACX_BCN_DTIM_OPTIONS, bb, sizeof(*bb));
+       if (ret < 0) {
+               wl1251_warning("failed to set rx config: %d", ret);
+               goto out;
+       }
+
+out:
+       kfree(bb);
+       return ret;
+}
+
+int wl1251_acx_aid(struct wl1251 *wl, u16 aid)
+{
+       struct acx_aid *acx_aid;
+       int ret;
+
+       wl1251_debug(DEBUG_ACX, "acx aid");
+
+       acx_aid = kzalloc(sizeof(*acx_aid), GFP_KERNEL);
+       if (!acx_aid) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       acx_aid->aid = aid;
+
+       ret = wl1251_cmd_configure(wl, ACX_AID, acx_aid, sizeof(*acx_aid));
+       if (ret < 0) {
+               wl1251_warning("failed to set aid: %d", ret);
+               goto out;
+       }
+
+out:
+       kfree(acx_aid);
+       return ret;
+}
+
+int wl1251_acx_event_mbox_mask(struct wl1251 *wl, u32 event_mask)
+{
+       struct acx_event_mask *mask;
+       int ret;
+
+       wl1251_debug(DEBUG_ACX, "acx event mbox mask");
+
+       mask = kzalloc(sizeof(*mask), GFP_KERNEL);
+       if (!mask) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       /* high event mask is unused */
+       mask->high_event_mask = 0xffffffff;
+
+       mask->event_mask = event_mask;
+
+       ret = wl1251_cmd_configure(wl, ACX_EVENT_MBOX_MASK,
+                                  mask, sizeof(*mask));
+       if (ret < 0) {
+               wl1251_warning("failed to set acx_event_mbox_mask: %d", ret);
+               goto out;
+       }
+
+out:
+       kfree(mask);
+       return ret;
+}
+
+int wl1251_acx_set_preamble(struct wl1251 *wl, enum acx_preamble_type preamble)
+{
+       struct acx_preamble *acx;
+       int ret;
+
+       wl1251_debug(DEBUG_ACX, "acx_set_preamble");
+
+       acx = kzalloc(sizeof(*acx), GFP_KERNEL);
+       if (!acx) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       acx->preamble = preamble;
+
+       ret = wl1251_cmd_configure(wl, ACX_PREAMBLE_TYPE, acx, sizeof(*acx));
+       if (ret < 0) {
+               wl1251_warning("Setting of preamble failed: %d", ret);
+               goto out;
+       }
+
+out:
+       kfree(acx);
+       return ret;
+}
+
+int wl1251_acx_cts_protect(struct wl1251 *wl,
+                          enum acx_ctsprotect_type ctsprotect)
+{
+       struct acx_ctsprotect *acx;
+       int ret;
+
+       wl1251_debug(DEBUG_ACX, "acx_set_ctsprotect");
+
+       acx = kzalloc(sizeof(*acx), GFP_KERNEL);
+       if (!acx) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       acx->ctsprotect = ctsprotect;
+
+       ret = wl1251_cmd_configure(wl, ACX_CTS_PROTECTION, acx, sizeof(*acx));
+       if (ret < 0) {
+               wl1251_warning("Setting of ctsprotect failed: %d", ret);
+               goto out;
+       }
+
+out:
+       kfree(acx);
+       return ret;
+}
+
+int wl1251_acx_tsf_info(struct wl1251 *wl, u64 *mactime)
+{
+       struct acx_tsf_info *tsf_info;
+       int ret;
+
+       tsf_info = kzalloc(sizeof(*tsf_info), GFP_KERNEL);
+       if (!tsf_info) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       ret = wl1251_cmd_interrogate(wl, ACX_TSF_INFO,
+                                    tsf_info, sizeof(*tsf_info));
+       if (ret < 0) {
+               wl1251_warning("ACX_FW_REV interrogate failed");
+               goto out;
+       }
+
+       *mactime = tsf_info->current_tsf_lsb |
+               (tsf_info->current_tsf_msb << 31);
+
+out:
+       kfree(tsf_info);
+       return ret;
+}
+
+int wl1251_acx_statistics(struct wl1251 *wl, struct acx_statistics *stats)
+{
+       int ret;
+
+       wl1251_debug(DEBUG_ACX, "acx statistics");
+
+       ret = wl1251_cmd_interrogate(wl, ACX_STATISTICS, stats,
+                                    sizeof(*stats));
+       if (ret < 0) {
+               wl1251_warning("acx statistics failed: %d", ret);
+               return -ENOMEM;
+       }
+
+       return 0;
+}
similarity index 86%
rename from drivers/net/wireless/wl12xx/acx.h
rename to drivers/net/wireless/wl12xx/wl1251_acx.h
index fb2d234..2e7b193 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * This file is part of wl12xx
+ * This file is part of wl1251
  *
  * Copyright (c) 1998-2007 Texas Instruments Incorporated
  * Copyright (C) 2008 Nokia Corporation
  *
  */
 
-#ifndef __WL12XX_ACX_H__
-#define __WL12XX_ACX_H__
+#ifndef __WL1251_ACX_H__
+#define __WL1251_ACX_H__
 
-#include "wl12xx.h"
+#include "wl1251.h"
+#include "wl1251_cmd.h"
 
 /* Target's information element */
 struct acx_header {
+       struct wl1251_cmd_header cmd;
+
+       /* acx (or information element) header */
        u16 id;
+
+       /* payload length (not including headers */
        u16 len;
 };
 
@@ -85,15 +91,15 @@ struct acx_revision {
        u32 hw_version;
 } __attribute__ ((packed));
 
-enum wl12xx_psm_mode {
+enum wl1251_psm_mode {
        /* Active mode */
-       WL12XX_PSM_CAM = 0,
+       WL1251_PSM_CAM = 0,
 
        /* Power save mode */
-       WL12XX_PSM_PS = 1,
+       WL1251_PSM_PS = 1,
 
        /* Extreme low power */
-       WL12XX_PSM_ELP = 2,
+       WL1251_PSM_ELP = 2,
 };
 
 struct acx_sleep_auth {
@@ -107,25 +113,6 @@ struct acx_sleep_auth {
        u8  padding[3];
 } __attribute__ ((packed));
 
-#define TIM_ELE_ID    5
-#define PARTIAL_VBM_MAX    251
-
-struct tim {
-       u8 identity;
-       u8 length;
-       u8 dtim_count;
-       u8 dtim_period;
-       u8 bitmap_ctrl;
-       u8 pvb_field[PARTIAL_VBM_MAX]; /* Partial Virtual Bitmap */
-} __attribute__ ((packed));
-
-/* Virtual Bit Map update */
-struct vbm_update_request {
-       __le16 len;
-       u8  padding[2];
-       struct tim tim;
-} __attribute__ ((packed));
-
 enum {
        HOSTIF_PCI_MASTER_HOST_INDIRECT,
        HOSTIF_PCI_MASTER_HOST_DIRECT,
@@ -202,7 +189,7 @@ struct acx_data_path_params_resp {
 #define RX_MSDU_LIFETIME_MAX       0xFFFFFFFF
 #define RX_MSDU_LIFETIME_DEF       512000
 
-struct rx_msdu_lifetime {
+struct acx_rx_msdu_lifetime {
        struct acx_header header;
 
        /*
@@ -368,7 +355,7 @@ struct acx_slot {
 #define ADDRESS_GROUP_MAX      (8)
 #define ADDRESS_GROUP_MAX_LEN  (ETH_ALEN * ADDRESS_GROUP_MAX)
 
-struct multicast_grp_addr_start {
+struct acx_dot11_grp_addr_tbl {
        struct acx_header header;
 
        u8 enabled;
@@ -730,22 +717,13 @@ struct acx_fw_gen_frame_rates {
 } __attribute__ ((packed));
 
 /* STA MAC */
-struct dot11_station_id {
+struct acx_dot11_station_id {
        struct acx_header header;
 
        u8 mac[ETH_ALEN];
        u8 pad[2];
 } __attribute__ ((packed));
 
-/* HW encryption keys */
-#define NUM_ACCESS_CATEGORIES_COPY 4
-#define MAX_KEY_SIZE 32
-
-/* When set, disable HW encryption */
-#define DF_ENCRYPTION_DISABLE      0x01
-/* When set, disable HW decryption */
-#define DF_SNIFF_MODE_ENABLE       0x80
-
 struct acx_feature_config {
        struct acx_header header;
 
@@ -753,67 +731,6 @@ struct acx_feature_config {
        u32 data_flow_options;
 } __attribute__ ((packed));
 
-enum acx_key_action {
-       KEY_ADD_OR_REPLACE = 1,
-       KEY_REMOVE         = 2,
-       KEY_SET_ID         = 3,
-       MAX_KEY_ACTION     = 0xffff,
-};
-
-enum acx_key_type {
-       KEY_WEP_DEFAULT       = 0,
-       KEY_WEP_ADDR          = 1,
-       KEY_AES_GROUP         = 4,
-       KEY_AES_PAIRWISE      = 5,
-       KEY_WEP_GROUP         = 6,
-       KEY_TKIP_MIC_GROUP    = 10,
-       KEY_TKIP_MIC_PAIRWISE = 11,
-};
-
-/*
- *
- * key_type_e   key size    key format
- * ----------   ---------   ----------
- * 0x00         5, 13, 29   Key data
- * 0x01         5, 13, 29   Key data
- * 0x04         16          16 bytes of key data
- * 0x05         16          16 bytes of key data
- * 0x0a         32          16 bytes of TKIP key data
- *                          8 bytes of RX MIC key data
- *                          8 bytes of TX MIC key data
- * 0x0b         32          16 bytes of TKIP key data
- *                          8 bytes of RX MIC key data
- *                          8 bytes of TX MIC key data
- *
- */
-
-struct acx_set_key {
-       /* Ignored for default WEP key */
-       u8 addr[ETH_ALEN];
-
-       /* key_action_e */
-       u16 key_action;
-
-       u16 reserved_1;
-
-       /* key size in bytes */
-       u8 key_size;
-
-       /* key_type_e */
-       u8 key_type;
-       u8 ssid_profile;
-
-       /*
-        * TKIP, AES: frame's key id field.
-        * For WEP default key: key id;
-        */
-       u8 id;
-       u8 reserved_2[6];
-       u8 key[MAX_KEY_SIZE];
-       u16 ac_seq_num16[NUM_ACCESS_CATEGORIES_COPY];
-       u32 ac_seq_num32[NUM_ACCESS_CATEGORIES_COPY];
-} __attribute__ ((packed));
-
 struct acx_current_tx_power {
        struct acx_header header;
 
@@ -839,26 +756,6 @@ struct acx_tsf_info {
        u8 pad[3];
 } __attribute__ ((packed));
 
-/* 802.11 PS */
-enum acx_ps_mode {
-       STATION_ACTIVE_MODE,
-       STATION_POWER_SAVE_MODE
-};
-
-struct acx_ps_params {
-       u8 ps_mode; /* STATION_* */
-       u8 send_null_data; /* Do we have to send NULL data packet ? */
-       u8 retries; /* Number of retires for the initial NULL data packet */
-
-        /*
-         * TUs during which the target stays awake after switching
-         * to power save mode.
-         */
-       u8 hang_over_period;
-       u16 null_data_rate;
-       u8 pad[2];
-} __attribute__ ((packed));
-
 enum acx_wake_up_event {
        WAKE_UP_EVENT_BEACON_BITMAP     = 0x01, /* Wake on every Beacon*/
        WAKE_UP_EVENT_DTIM_BITMAP       = 0x02, /* Wake on every DTIM*/
@@ -892,6 +789,7 @@ enum acx_preamble_type {
 
 struct acx_preamble {
        struct acx_header header;
+
        /*
         * When set, the WiLink transmits the frames with a short preamble and
         * when cleared, the WiLink transmits the frames with a long preamble.
@@ -1210,36 +1108,39 @@ enum {
 };
 
 
-int wl12xx_acx_frame_rates(struct wl12xx *wl, u8 ctrl_rate, u8 ctrl_mod,
+int wl1251_acx_frame_rates(struct wl1251 *wl, u8 ctrl_rate, u8 ctrl_mod,
                           u8 mgt_rate, u8 mgt_mod);
-int wl12xx_acx_station_id(struct wl12xx *wl);
-int wl12xx_acx_default_key(struct wl12xx *wl, u8 key_id);
-int wl12xx_acx_wake_up_conditions(struct wl12xx *wl, u8 listen_interval);
-int wl12xx_acx_sleep_auth(struct wl12xx *wl, u8 sleep_auth);
-int wl12xx_acx_fw_version(struct wl12xx *wl, char *buf, size_t len);
-int wl12xx_acx_tx_power(struct wl12xx *wl, int power);
-int wl12xx_acx_feature_cfg(struct wl12xx *wl);
-int wl12xx_acx_mem_map(struct wl12xx *wl, void *mem_map, size_t len);
-int wl12xx_acx_data_path_params(struct wl12xx *wl,
+int wl1251_acx_station_id(struct wl1251 *wl);
+int wl1251_acx_default_key(struct wl1251 *wl, u8 key_id);
+int wl1251_acx_wake_up_conditions(struct wl1251 *wl, u8 wake_up_event,
+                                 u8 listen_interval);
+int wl1251_acx_sleep_auth(struct wl1251 *wl, u8 sleep_auth);
+int wl1251_acx_fw_version(struct wl1251 *wl, char *buf, size_t len);
+int wl1251_acx_tx_power(struct wl1251 *wl, int power);
+int wl1251_acx_feature_cfg(struct wl1251 *wl);
+int wl1251_acx_mem_map(struct wl1251 *wl,
+                      struct acx_header *mem_map, size_t len);
+int wl1251_acx_data_path_params(struct wl1251 *wl,
                                struct acx_data_path_params_resp *data_path);
-int wl12xx_acx_rx_msdu_life_time(struct wl12xx *wl, u32 life_time);
-int wl12xx_acx_rx_config(struct wl12xx *wl, u32 config, u32 filter);
-int wl12xx_acx_pd_threshold(struct wl12xx *wl);
-int wl12xx_acx_slot(struct wl12xx *wl, enum acx_slot_type slot_time);
-int wl12xx_acx_group_address_tbl(struct wl12xx *wl);
-int wl12xx_acx_service_period_timeout(struct wl12xx *wl);
-int wl12xx_acx_rts_threshold(struct wl12xx *wl, u16 rts_threshold);
-int wl12xx_acx_beacon_filter_opt(struct wl12xx *wl);
-int wl12xx_acx_beacon_filter_table(struct wl12xx *wl);
-int wl12xx_acx_sg_enable(struct wl12xx *wl);
-int wl12xx_acx_sg_cfg(struct wl12xx *wl);
-int wl12xx_acx_cca_threshold(struct wl12xx *wl);
-int wl12xx_acx_bcn_dtim_options(struct wl12xx *wl);
-int wl12xx_acx_aid(struct wl12xx *wl, u16 aid);
-int wl12xx_acx_event_mbox_mask(struct wl12xx *wl, u32 event_mask);
-int wl12xx_acx_set_preamble(struct wl12xx *wl, enum acx_preamble_type preamble);
-int wl12xx_acx_cts_protect(struct wl12xx *wl,
+int wl1251_acx_rx_msdu_life_time(struct wl1251 *wl, u32 life_time);
+int wl1251_acx_rx_config(struct wl1251 *wl, u32 config, u32 filter);
+int wl1251_acx_pd_threshold(struct wl1251 *wl);
+int wl1251_acx_slot(struct wl1251 *wl, enum acx_slot_type slot_time);
+int wl1251_acx_group_address_tbl(struct wl1251 *wl);
+int wl1251_acx_service_period_timeout(struct wl1251 *wl);
+int wl1251_acx_rts_threshold(struct wl1251 *wl, u16 rts_threshold);
+int wl1251_acx_beacon_filter_opt(struct wl1251 *wl);
+int wl1251_acx_beacon_filter_table(struct wl1251 *wl);
+int wl1251_acx_sg_enable(struct wl1251 *wl);
+int wl1251_acx_sg_cfg(struct wl1251 *wl);
+int wl1251_acx_cca_threshold(struct wl1251 *wl);
+int wl1251_acx_bcn_dtim_options(struct wl1251 *wl);
+int wl1251_acx_aid(struct wl1251 *wl, u16 aid);
+int wl1251_acx_event_mbox_mask(struct wl1251 *wl, u32 event_mask);
+int wl1251_acx_set_preamble(struct wl1251 *wl, enum acx_preamble_type preamble);
+int wl1251_acx_cts_protect(struct wl1251 *wl,
                            enum acx_ctsprotect_type ctsprotect);
-int wl12xx_acx_statistics(struct wl12xx *wl, struct acx_statistics *stats);
+int wl1251_acx_statistics(struct wl1251 *wl, struct acx_statistics *stats);
+int wl1251_acx_tsf_info(struct wl1251 *wl, u64 *mactime);
 
-#endif /* __WL12XX_ACX_H__ */
+#endif /* __WL1251_ACX_H__ */
similarity index 67%
rename from drivers/net/wireless/wl12xx/boot.c
rename to drivers/net/wireless/wl12xx/wl1251_boot.c
index 48ac08c..d8a155d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * This file is part of wl12xx
+ * This file is part of wl1251
  *
  * Copyright (C) 2008 Nokia Corporation
  *
 #include <linux/gpio.h>
 
 #include "reg.h"
-#include "boot.h"
-#include "spi.h"
-#include "event.h"
+#include "wl1251_boot.h"
+#include "wl1251_spi.h"
+#include "wl1251_event.h"
 
-static void wl12xx_boot_enable_interrupts(struct wl12xx *wl)
+static void wl1251_boot_enable_interrupts(struct wl1251 *wl)
 {
        enable_irq(wl->irq);
 }
 
-void wl12xx_boot_target_enable_interrupts(struct wl12xx *wl)
+void wl1251_boot_target_enable_interrupts(struct wl1251 *wl)
 {
-       wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_MASK, ~(wl->intr_mask));
-       wl12xx_reg_write32(wl, HI_CFG, HI_CFG_DEF_VAL);
+       wl1251_reg_write32(wl, ACX_REG_INTERRUPT_MASK, ~(wl->intr_mask));
+       wl1251_reg_write32(wl, HI_CFG, HI_CFG_DEF_VAL);
 }
 
-int wl12xx_boot_soft_reset(struct wl12xx *wl)
+int wl1251_boot_soft_reset(struct wl1251 *wl)
 {
        unsigned long timeout;
        u32 boot_data;
 
        /* perform soft reset */
-       wl12xx_reg_write32(wl, ACX_REG_SLV_SOFT_RESET, ACX_SLV_SOFT_RESET_BIT);
+       wl1251_reg_write32(wl, ACX_REG_SLV_SOFT_RESET, ACX_SLV_SOFT_RESET_BIT);
 
        /* SOFT_RESET is self clearing */
        timeout = jiffies + usecs_to_jiffies(SOFT_RESET_MAX_TIME);
        while (1) {
-               boot_data = wl12xx_reg_read32(wl, ACX_REG_SLV_SOFT_RESET);
-               wl12xx_debug(DEBUG_BOOT, "soft reset bootdata 0x%x", boot_data);
+               boot_data = wl1251_reg_read32(wl, ACX_REG_SLV_SOFT_RESET);
+               wl1251_debug(DEBUG_BOOT, "soft reset bootdata 0x%x", boot_data);
                if ((boot_data & ACX_SLV_SOFT_RESET_BIT) == 0)
                        break;
 
                if (time_after(jiffies, timeout)) {
                        /* 1.2 check pWhalBus->uSelfClearTime if the
                         * timeout was reached */
-                       wl12xx_error("soft reset timeout");
+                       wl1251_error("soft reset timeout");
                        return -1;
                }
 
@@ -66,15 +66,15 @@ int wl12xx_boot_soft_reset(struct wl12xx *wl)
        }
 
        /* disable Rx/Tx */
-       wl12xx_reg_write32(wl, ENABLE, 0x0);
+       wl1251_reg_write32(wl, ENABLE, 0x0);
 
        /* disable auto calibration on start*/
-       wl12xx_reg_write32(wl, SPARE_A2, 0xffff);
+       wl1251_reg_write32(wl, SPARE_A2, 0xffff);
 
        return 0;
 }
 
-int wl12xx_boot_init_seq(struct wl12xx *wl)
+int wl1251_boot_init_seq(struct wl1251 *wl)
 {
        u32 scr_pad6, init_data, tmp, elp_cmd, ref_freq;
 
@@ -96,23 +96,23 @@ int wl12xx_boot_init_seq(struct wl12xx *wl)
        };
 
        /* read NVS params */
-       scr_pad6 = wl12xx_reg_read32(wl, SCR_PAD6);
-       wl12xx_debug(DEBUG_BOOT, "scr_pad6 0x%x", scr_pad6);
+       scr_pad6 = wl1251_reg_read32(wl, SCR_PAD6);
+       wl1251_debug(DEBUG_BOOT, "scr_pad6 0x%x", scr_pad6);
 
        /* read ELP_CMD */
-       elp_cmd = wl12xx_reg_read32(wl, ELP_CMD);
-       wl12xx_debug(DEBUG_BOOT, "elp_cmd 0x%x", elp_cmd);
+       elp_cmd = wl1251_reg_read32(wl, ELP_CMD);
+       wl1251_debug(DEBUG_BOOT, "elp_cmd 0x%x", elp_cmd);
 
        /* set the BB calibration time to be 300 usec (PLL_CAL_TIME) */
        ref_freq = scr_pad6 & 0x000000FF;
-       wl12xx_debug(DEBUG_BOOT, "ref_freq 0x%x", ref_freq);
+       wl1251_debug(DEBUG_BOOT, "ref_freq 0x%x", ref_freq);
 
-       wl12xx_reg_write32(wl, PLL_CAL_TIME, 0x9);
+       wl1251_reg_write32(wl, PLL_CAL_TIME, 0x9);
 
        /*
         * PG 1.2: set the clock buffer time to be 210 usec (CLK_BUF_TIME)
         */
-       wl12xx_reg_write32(wl, CLK_BUF_TIME, 0x6);
+       wl1251_reg_write32(wl, CLK_BUF_TIME, 0x6);
 
        /*
         * set the clock detect feature to work in the restart wu procedure
@@ -120,18 +120,18 @@ int wl12xx_boot_init_seq(struct wl12xx *wl)
         * (ELP_CFG_MODE[13:12])
         */
        tmp = ((scr_pad6 & 0x0000FF00) << 4) | 0x00004000;
-       wl12xx_reg_write32(wl, ELP_CFG_MODE, tmp);
+       wl1251_reg_write32(wl, ELP_CFG_MODE, tmp);
 
        /* PG 1.2: enable the BB PLL fix. Enable the PLL_LIMP_CLK_EN_CMD */
        elp_cmd |= 0x00000040;
-       wl12xx_reg_write32(wl, ELP_CMD, elp_cmd);
+       wl1251_reg_write32(wl, ELP_CMD, elp_cmd);
 
        /* PG 1.2: Set the BB PLL stable time to be 1000usec
         * (PLL_STABLE_TIME) */
-       wl12xx_reg_write32(wl, CFG_PLL_SYNC_CNT, 0x20);
+       wl1251_reg_write32(wl, CFG_PLL_SYNC_CNT, 0x20);
 
        /* PG 1.2: read clock request time */
-       init_data = wl12xx_reg_read32(wl, CLK_REQ_TIME);
+       init_data = wl1251_reg_read32(wl, CLK_REQ_TIME);
 
        /*
         * PG 1.2: set the clock request time to be ref_clk_settling_time -
@@ -141,35 +141,35 @@ int wl12xx_boot_init_seq(struct wl12xx *wl)
                tmp = init_data - 0x21;
        else
                tmp = 0;
-       wl12xx_reg_write32(wl, CLK_REQ_TIME, tmp);
+       wl1251_reg_write32(wl, CLK_REQ_TIME, tmp);
 
        /* set BB PLL configurations in RF AFE */
-       wl12xx_reg_write32(wl, 0x003058cc, 0x4B5);
+       wl1251_reg_write32(wl, 0x003058cc, 0x4B5);
 
        /* set RF_AFE_REG_5 */
-       wl12xx_reg_write32(wl, 0x003058d4, 0x50);
+       wl1251_reg_write32(wl, 0x003058d4, 0x50);
 
        /* set RF_AFE_CTRL_REG_2 */
-       wl12xx_reg_write32(wl, 0x00305948, 0x11c001);
+       wl1251_reg_write32(wl, 0x00305948, 0x11c001);
 
        /*
         * change RF PLL and BB PLL divider for VCO clock and adjust VCO
         * bais current(RF_AFE_REG_13)
         */
-       wl12xx_reg_write32(wl, 0x003058f4, 0x1e);
+       wl1251_reg_write32(wl, 0x003058f4, 0x1e);
 
        /* set BB PLL configurations */
        tmp = LUT[ref_freq][LUT_PARAM_INTEGER_DIVIDER] | 0x00017000;
-       wl12xx_reg_write32(wl, 0x00305840, tmp);
+       wl1251_reg_write32(wl, 0x00305840, tmp);
 
        /* set fractional divider according to Appendix C-BB PLL
         * Calculations
         */
        tmp = LUT[ref_freq][LUT_PARAM_FRACTIONAL_DIVIDER];
-       wl12xx_reg_write32(wl, 0x00305844, tmp);
+       wl1251_reg_write32(wl, 0x00305844, tmp);
 
        /* set the initial data for the sigma delta */
-       wl12xx_reg_write32(wl, 0x00305848, 0x3039);
+       wl1251_reg_write32(wl, 0x00305848, 0x3039);
 
        /*
         * set the accumulator attenuation value, calibration loop1
@@ -178,14 +178,14 @@ int wl12xx_boot_init_seq(struct wl12xx *wl)
         */
        tmp = (LUT[ref_freq][LUT_PARAM_ATTN_BB] << 16) |
                (LUT[ref_freq][LUT_PARAM_ALPHA_BB] << 12) | 0x1;
-       wl12xx_reg_write32(wl, 0x00305854, tmp);
+       wl1251_reg_write32(wl, 0x00305854, tmp);
 
        /*
         * set the calibration stop time after holdoff time expires and set
         * settling time HOLD_OFF_TIME_BB
         */
        tmp = LUT[ref_freq][LUT_PARAM_STOP_TIME_BB] | 0x000A0000;
-       wl12xx_reg_write32(wl, 0x00305858, tmp);
+       wl1251_reg_write32(wl, 0x00305858, tmp);
 
        /*
         * set BB PLL Loop filter capacitor3- BB_C3[2:0] and set BB PLL
@@ -193,7 +193,7 @@ int wl12xx_boot_init_seq(struct wl12xx *wl)
         * BB_ILOOPF[7:3]
         */
        tmp = LUT[ref_freq][LUT_PARAM_BB_PLL_LOOP_FILTER] | 0x00000030;
-       wl12xx_reg_write32(wl, 0x003058f8, tmp);
+       wl1251_reg_write32(wl, 0x003058f8, tmp);
 
        /*
         * set regulator output voltage for n divider to
@@ -201,10 +201,10 @@ int wl12xx_boot_init_seq(struct wl12xx *wl)
         * set BB PLL Loop filter capacitor2- BB_C2[7:5], set gain of BB
         * PLL auto-call to normal mode- BB_CALGAIN_3DB[8]
         */
-       wl12xx_reg_write32(wl, 0x003058f0, 0x29);
+       wl1251_reg_write32(wl, 0x003058f0, 0x29);
 
        /* enable restart wakeup sequence (ELP_CMD[0]) */
-       wl12xx_reg_write32(wl, ELP_CMD, elp_cmd | 0x1);
+       wl1251_reg_write32(wl, ELP_CMD, elp_cmd | 0x1);
 
        /* restart sequence completed */
        udelay(2000);
@@ -212,19 +212,19 @@ int wl12xx_boot_init_seq(struct wl12xx *wl)
        return 0;
 }
 
-int wl12xx_boot_run_firmware(struct wl12xx *wl)
+int wl1251_boot_run_firmware(struct wl1251 *wl)
 {
        int loop, ret;
        u32 chip_id, interrupt;
 
        wl->chip.op_set_ecpu_ctrl(wl, ECPU_CONTROL_HALT);
 
-       chip_id = wl12xx_reg_read32(wl, CHIP_ID_B);
+       chip_id = wl1251_reg_read32(wl, CHIP_ID_B);
 
-       wl12xx_debug(DEBUG_BOOT, "chip id after firmware boot: 0x%x", chip_id);
+       wl1251_debug(DEBUG_BOOT, "chip id after firmware boot: 0x%x", chip_id);
 
        if (chip_id != wl->chip.id) {
-               wl12xx_error("chip id doesn't match after firmware boot");
+               wl1251_error("chip id doesn't match after firmware boot");
                return -EIO;
        }
 
@@ -232,63 +232,65 @@ int wl12xx_boot_run_firmware(struct wl12xx *wl)
        loop = 0;
        while (loop++ < INIT_LOOP) {
                udelay(INIT_LOOP_DELAY);
-               interrupt = wl12xx_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR);
+               interrupt = wl1251_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR);
 
                if (interrupt == 0xffffffff) {
-                       wl12xx_error("error reading hardware complete "
+                       wl1251_error("error reading hardware complete "
                                     "init indication");
                        return -EIO;
                }
                /* check that ACX_INTR_INIT_COMPLETE is enabled */
                else if (interrupt & wl->chip.intr_init_complete) {
-                       wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_ACK,
+                       wl1251_reg_write32(wl, ACX_REG_INTERRUPT_ACK,
                                           wl->chip.intr_init_complete);
                        break;
                }
        }
 
        if (loop >= INIT_LOOP) {
-               wl12xx_error("timeout waiting for the hardware to "
+               wl1251_error("timeout waiting for the hardware to "
                             "complete initialization");
                return -EIO;
        }
 
        /* get hardware config command mail box */
-       wl->cmd_box_addr = wl12xx_reg_read32(wl, REG_COMMAND_MAILBOX_PTR);
+       wl->cmd_box_addr = wl1251_reg_read32(wl, REG_COMMAND_MAILBOX_PTR);
 
        /* get hardware config event mail box */
-       wl->event_box_addr = wl12xx_reg_read32(wl, REG_EVENT_MAILBOX_PTR);
+       wl->event_box_addr = wl1251_reg_read32(wl, REG_EVENT_MAILBOX_PTR);
 
        /* set the working partition to its "running" mode offset */
-       wl12xx_set_partition(wl,
+       wl1251_set_partition(wl,
                             wl->chip.p_table[PART_WORK].mem.start,
                             wl->chip.p_table[PART_WORK].mem.size,
                             wl->chip.p_table[PART_WORK].reg.start,
                             wl->chip.p_table[PART_WORK].reg.size);
 
-       wl12xx_debug(DEBUG_MAILBOX, "cmd_box_addr 0x%x event_box_addr 0x%x",
+       wl1251_debug(DEBUG_MAILBOX, "cmd_box_addr 0x%x event_box_addr 0x%x",
                     wl->cmd_box_addr, wl->event_box_addr);
 
+       wl->chip.op_fw_version(wl);
+
        /*
         * in case of full asynchronous mode the firmware event must be
         * ready to receive event from the command mailbox
         */
 
        /* enable gpio interrupts */
-       wl12xx_boot_enable_interrupts(wl);
+       wl1251_boot_enable_interrupts(wl);
 
        wl->chip.op_target_enable_interrupts(wl);
 
        /* unmask all mbox events  */
        wl->event_mask = 0xffffffff;
 
-       ret = wl12xx_event_unmask(wl);
+       ret = wl1251_event_unmask(wl);
        if (ret < 0) {
-               wl12xx_error("EVENT mask setting failed");
+               wl1251_error("EVENT mask setting failed");
                return ret;
        }
 
-       wl12xx_event_mbox_config(wl);
+       wl1251_event_mbox_config(wl);
 
        /* firmware startup completed */
        return 0;
similarity index 78%
rename from drivers/net/wireless/wl12xx/boot.h
rename to drivers/net/wireless/wl12xx/wl1251_boot.h
index 4fa7313..798362d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * This file is part of wl12xx
+ * This file is part of wl1251
  *
  * Copyright (C) 2008 Nokia Corporation
  *
 #ifndef __BOOT_H__
 #define __BOOT_H__
 
-#include "wl12xx.h"
+#include "wl1251.h"
 
-int wl12xx_boot_soft_reset(struct wl12xx *wl);
-int wl12xx_boot_init_seq(struct wl12xx *wl);
-int wl12xx_boot_run_firmware(struct wl12xx *wl);
-void wl12xx_boot_target_enable_interrupts(struct wl12xx *wl);
+int wl1251_boot_soft_reset(struct wl1251 *wl);
+int wl1251_boot_init_seq(struct wl1251 *wl);
+int wl1251_boot_run_firmware(struct wl1251 *wl);
+void wl1251_boot_target_enable_interrupts(struct wl1251 *wl);
 
 /* number of times we try to read the INIT interrupt */
 #define INIT_LOOP 20000
diff --git a/drivers/net/wireless/wl12xx/wl1251_cmd.c b/drivers/net/wireless/wl12xx/wl1251_cmd.c
new file mode 100644 (file)
index 0000000..dc04d1f
--- /dev/null
@@ -0,0 +1,428 @@
+#include "wl1251_cmd.h"
+
+#include <linux/module.h>
+#include <linux/crc7.h>
+#include <linux/spi/spi.h>
+
+#include "wl1251.h"
+#include "reg.h"
+#include "wl1251_spi.h"
+#include "wl1251_ps.h"
+#include "wl1251_acx.h"
+
+/**
+ * send command to firmware
+ *
+ * @wl: wl struct
+ * @id: command id
+ * @buf: buffer containing the command, must work with dma
+ * @len: length of the buffer
+ */
+int wl1251_cmd_send(struct wl1251 *wl, u16 id, void *buf, size_t len)
+{
+       struct wl1251_cmd_header *cmd;
+       unsigned long timeout;
+       u32 intr;
+       int ret = 0;
+
+       cmd = buf;
+       cmd->id = id;
+       cmd->status = 0;
+
+       WARN_ON(len % 4 != 0);
+
+       wl1251_spi_mem_write(wl, wl->cmd_box_addr, buf, len);
+
+       wl1251_reg_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_CMD);
+
+       timeout = jiffies + msecs_to_jiffies(WL1251_COMMAND_TIMEOUT);
+
+       intr = wl1251_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR);
+       while (!(intr & wl->chip.intr_cmd_complete)) {
+               if (time_after(jiffies, timeout)) {
+                       wl1251_error("command complete timeout");
+                       ret = -ETIMEDOUT;
+                       goto out;
+               }
+
+               msleep(1);
+
+               intr = wl1251_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR);
+       }
+
+       wl1251_reg_write32(wl, ACX_REG_INTERRUPT_ACK,
+                          wl->chip.intr_cmd_complete);
+
+out:
+       return ret;
+}
+
+/**
+ * send test command to firmware
+ *
+ * @wl: wl struct
+ * @buf: buffer containing the command, with all headers, must work with dma
+ * @len: length of the buffer
+ * @answer: is answer needed
+ */
+int wl1251_cmd_test(struct wl1251 *wl, void *buf, size_t buf_len, u8 answer)
+{
+       int ret;
+
+       wl1251_debug(DEBUG_CMD, "cmd test");
+
+       ret = wl1251_cmd_send(wl, CMD_TEST, buf, buf_len);
+
+       if (ret < 0) {
+               wl1251_warning("TEST command failed");
+               return ret;
+       }
+
+       if (answer) {
+               struct wl1251_command *cmd_answer;
+
+               /*
+                * The test command got in, we can read the answer.
+                * The answer would be a wl1251_command, where the
+                * parameter array contains the actual answer.
+                */
+               wl1251_spi_mem_read(wl, wl->cmd_box_addr, buf, buf_len);
+
+               cmd_answer = buf;
+
+               if (cmd_answer->header.status != CMD_STATUS_SUCCESS)
+                       wl1251_error("TEST command answer error: %d",
+                                    cmd_answer->header.status);
+       }
+
+       return 0;
+}
+
+/**
+ * read acx from firmware
+ *
+ * @wl: wl struct
+ * @id: acx id
+ * @buf: buffer for the response, including all headers, must work with dma
+ * @len: lenght of buf
+ */
+int wl1251_cmd_interrogate(struct wl1251 *wl, u16 id, void *buf, size_t len)
+{
+       struct acx_header *acx = buf;
+       int ret;
+
+       wl1251_debug(DEBUG_CMD, "cmd interrogate");
+
+       acx->id = id;
+
+       /* payload length, does not include any headers */
+       acx->len = len - sizeof(*acx);
+
+       ret = wl1251_cmd_send(wl, CMD_INTERROGATE, acx, sizeof(*acx));
+       if (ret < 0) {
+               wl1251_error("INTERROGATE command failed");
+               goto out;
+       }
+
+       /* the interrogate command got in, we can read the answer */
+       wl1251_spi_mem_read(wl, wl->cmd_box_addr, buf, len);
+
+       acx = buf;
+       if (acx->cmd.status != CMD_STATUS_SUCCESS)
+               wl1251_error("INTERROGATE command error: %d",
+                            acx->cmd.status);
+
+out:
+       return ret;
+}
+
+/**
+ * write acx value to firmware
+ *
+ * @wl: wl struct
+ * @id: acx id
+ * @buf: buffer containing acx, including all headers, must work with dma
+ * @len: length of buf
+ */
+int wl1251_cmd_configure(struct wl1251 *wl, u16 id, void *buf, size_t len)
+{
+       struct acx_header *acx = buf;
+       int ret;
+
+       wl1251_debug(DEBUG_CMD, "cmd configure");
+
+       acx->id = id;
+
+       /* payload length, does not include any headers */
+       acx->len = len - sizeof(*acx);
+
+       ret = wl1251_cmd_send(wl, CMD_CONFIGURE, acx, len);
+       if (ret < 0) {
+               wl1251_warning("CONFIGURE command NOK");
+               return ret;
+       }
+
+       return 0;
+}
+
+int wl1251_cmd_vbm(struct wl1251 *wl, u8 identity,
+                  void *bitmap, u16 bitmap_len, u8 bitmap_control)
+{
+       struct wl1251_cmd_vbm_update *vbm;
+       int ret;
+
+       wl1251_debug(DEBUG_CMD, "cmd vbm");
+
+       vbm = kzalloc(sizeof(*vbm), GFP_KERNEL);
+       if (!vbm) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       /* Count and period will be filled by the target */
+       vbm->tim.bitmap_ctrl = bitmap_control;
+       if (bitmap_len > PARTIAL_VBM_MAX) {
+               wl1251_warning("cmd vbm len is %d B, truncating to %d",
+                              bitmap_len, PARTIAL_VBM_MAX);
+               bitmap_len = PARTIAL_VBM_MAX;
+       }
+       memcpy(vbm->tim.pvb_field, bitmap, bitmap_len);
+       vbm->tim.identity = identity;
+       vbm->tim.length = bitmap_len + 3;
+
+       vbm->len = cpu_to_le16(bitmap_len + 5);
+
+       ret = wl1251_cmd_send(wl, CMD_VBM, vbm, sizeof(*vbm));
+       if (ret < 0) {
+               wl1251_error("VBM command failed");
+               goto out;
+       }
+
+out:
+       kfree(vbm);
+       return 0;
+}
+
+int wl1251_cmd_data_path(struct wl1251 *wl, u8 channel, bool enable)
+{
+       struct cmd_enabledisable_path *cmd;
+       int ret;
+       u16 cmd_rx, cmd_tx;
+
+       wl1251_debug(DEBUG_CMD, "cmd data path");
+
+       cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+       if (!cmd) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       cmd->channel = channel;
+
+       if (enable) {
+               cmd_rx = CMD_ENABLE_RX;
+               cmd_tx = CMD_ENABLE_TX;
+       } else {
+               cmd_rx = CMD_DISABLE_RX;
+               cmd_tx = CMD_DISABLE_TX;
+       }
+
+       ret = wl1251_cmd_send(wl, cmd_rx, cmd, sizeof(*cmd));
+       if (ret < 0) {
+               wl1251_error("rx %s cmd for channel %d failed",
+                            enable ? "start" : "stop", channel);
+               goto out;
+       }
+
+       wl1251_debug(DEBUG_BOOT, "rx %s cmd channel %d",
+                    enable ? "start" : "stop", channel);
+
+       ret = wl1251_cmd_send(wl, cmd_tx, cmd, sizeof(*cmd));
+       if (ret < 0) {
+               wl1251_error("tx %s cmd for channel %d failed",
+                            enable ? "start" : "stop", channel);
+               return ret;
+       }
+
+       wl1251_debug(DEBUG_BOOT, "tx %s cmd channel %d",
+                    enable ? "start" : "stop", channel);
+
+out:
+       kfree(cmd);
+       return ret;
+}
+
+int wl1251_cmd_join(struct wl1251 *wl, u8 bss_type, u8 dtim_interval,
+                   u16 beacon_interval, u8 wait)
+{
+       unsigned long timeout;
+       struct cmd_join *join;
+       int ret, i;
+       u8 *bssid;
+
+       join = kzalloc(sizeof(*join), GFP_KERNEL);
+       if (!join) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       /* FIXME: this should be in main.c */
+       ret = wl1251_acx_frame_rates(wl, DEFAULT_HW_GEN_TX_RATE,
+                                    DEFAULT_HW_GEN_MODULATION_TYPE,
+                                    wl->tx_mgmt_frm_rate,
+                                    wl->tx_mgmt_frm_mod);
+       if (ret < 0)
+               goto out;
+
+       wl1251_debug(DEBUG_CMD, "cmd join");
+
+       /* Reverse order BSSID */
+       bssid = (u8 *) &join->bssid_lsb;
+       for (i = 0; i < ETH_ALEN; i++)
+               bssid[i] = wl->bssid[ETH_ALEN - i - 1];
+
+       join->rx_config_options = wl->rx_config;
+       join->rx_filter_options = wl->rx_filter;
+
+       join->basic_rate_set = RATE_MASK_1MBPS | RATE_MASK_2MBPS |
+               RATE_MASK_5_5MBPS | RATE_MASK_11MBPS;
+
+       join->beacon_interval = beacon_interval;
+       join->dtim_interval = dtim_interval;
+       join->bss_type = bss_type;
+       join->channel = wl->channel;
+       join->ctrl = JOIN_CMD_CTRL_TX_FLUSH;
+
+       ret = wl1251_cmd_send(wl, CMD_START_JOIN, join, sizeof(*join));
+       if (ret < 0) {
+               wl1251_error("failed to initiate cmd join");
+               goto out;
+       }
+
+       timeout = msecs_to_jiffies(JOIN_TIMEOUT);
+
+       /*
+        * ugly hack: we should wait for JOIN_EVENT_COMPLETE_ID but to
+        * simplify locking we just sleep instead, for now
+        */
+       if (wait)
+               msleep(10);
+
+out:
+       kfree(join);
+       return ret;
+}
+
+int wl1251_cmd_ps_mode(struct wl1251 *wl, u8 ps_mode)
+{
+       struct wl1251_cmd_ps_params *ps_params = NULL;
+       int ret = 0;
+
+       /* FIXME: this should be in ps.c */
+       ret = wl1251_acx_wake_up_conditions(wl, WAKE_UP_EVENT_DTIM_BITMAP,
+                                           wl->listen_int);
+       if (ret < 0) {
+               wl1251_error("couldn't set wake up conditions");
+               goto out;
+       }
+
+       wl1251_debug(DEBUG_CMD, "cmd set ps mode");
+
+       ps_params = kzalloc(sizeof(*ps_params), GFP_KERNEL);
+       if (!ps_params) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       ps_params->ps_mode = ps_mode;
+       ps_params->send_null_data = 1;
+       ps_params->retries = 5;
+       ps_params->hang_over_period = 128;
+       ps_params->null_data_rate = 1; /* 1 Mbps */
+
+       ret = wl1251_cmd_send(wl, CMD_SET_PS_MODE, ps_params,
+                             sizeof(*ps_params));
+       if (ret < 0) {
+               wl1251_error("cmd set_ps_mode failed");
+               goto out;
+       }
+
+out:
+       kfree(ps_params);
+       return ret;
+}
+
+int wl1251_cmd_read_memory(struct wl1251 *wl, u32 addr, void *answer,
+                          size_t len)
+{
+       struct cmd_read_write_memory *cmd;
+       int ret = 0;
+
+       wl1251_debug(DEBUG_CMD, "cmd read memory");
+
+       cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+       if (!cmd) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       WARN_ON(len > MAX_READ_SIZE);
+       len = min_t(size_t, len, MAX_READ_SIZE);
+
+       cmd->addr = addr;
+       cmd->size = len;
+
+       ret = wl1251_cmd_send(wl, CMD_READ_MEMORY, cmd, sizeof(*cmd));
+       if (ret < 0) {
+               wl1251_error("read memory command failed: %d", ret);
+               goto out;
+       }
+
+       /* the read command got in, we can now read the answer */
+       wl1251_spi_mem_read(wl, wl->cmd_box_addr, cmd, sizeof(*cmd));
+
+       if (cmd->header.status != CMD_STATUS_SUCCESS)
+               wl1251_error("error in read command result: %d",
+                            cmd->header.status);
+
+       memcpy(answer, cmd->value, len);
+
+out:
+       kfree(cmd);
+       return ret;
+}
+
+int wl1251_cmd_template_set(struct wl1251 *wl, u16 cmd_id,
+                           void *buf, size_t buf_len)
+{
+       struct wl1251_cmd_packet_template *cmd;
+       size_t cmd_len;
+       int ret = 0;
+
+       wl1251_debug(DEBUG_CMD, "cmd template %d", cmd_id);
+
+       WARN_ON(buf_len > WL1251_MAX_TEMPLATE_SIZE);
+       buf_len = min_t(size_t, buf_len, WL1251_MAX_TEMPLATE_SIZE);
+       cmd_len = ALIGN(sizeof(*cmd) + buf_len, 4);
+
+       cmd = kzalloc(cmd_len, GFP_KERNEL);
+       if (!cmd) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       cmd->size = cpu_to_le16(buf_len);
+
+       if (buf)
+               memcpy(cmd->data, buf, buf_len);
+
+       ret = wl1251_cmd_send(wl, cmd_id, cmd, cmd_len);
+       if (ret < 0) {
+               wl1251_warning("cmd set_template failed: %d", ret);
+               goto out;
+       }
+
+out:
+       kfree(cmd);
+       return ret;
+}
similarity index 60%
rename from drivers/net/wireless/wl12xx/cmd.h
rename to drivers/net/wireless/wl12xx/wl1251_cmd.h
index aa307dc..64f228d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * This file is part of wl12xx
+ * This file is part of wl1251
  *
  * Copyright (c) 1998-2007 Texas Instruments Incorporated
  * Copyright (C) 2008 Nokia Corporation
  *
  */
 
-#ifndef __WL12XX_CMD_H__
-#define __WL12XX_CMD_H__
+#ifndef __WL1251_CMD_H__
+#define __WL1251_CMD_H__
 
-#include "wl12xx.h"
+#include "wl1251.h"
 
-int wl12xx_cmd_send(struct wl12xx *wl, u16 type, void *buf, size_t buf_len);
-int wl12xx_cmd_test(struct wl12xx *wl, void *buf, size_t buf_len, u8 answer);
-int wl12xx_cmd_interrogate(struct wl12xx *wl, u16 ie_id, u16 ie_len,
-                          void *answer);
-int wl12xx_cmd_configure(struct wl12xx *wl, void *ie, int ie_len);
-int wl12xx_cmd_vbm(struct wl12xx *wl, u8 identity,
+struct acx_header;
+
+int wl1251_cmd_send(struct wl1251 *wl, u16 type, void *buf, size_t buf_len);
+int wl1251_cmd_test(struct wl1251 *wl, void *buf, size_t buf_len, u8 answer);
+int wl1251_cmd_interrogate(struct wl1251 *wl, u16 id, void *buf, size_t len);
+int wl1251_cmd_configure(struct wl1251 *wl, u16 id, void *buf, size_t len);
+int wl1251_cmd_vbm(struct wl1251 *wl, u8 identity,
                   void *bitmap, u16 bitmap_len, u8 bitmap_control);
-int wl12xx_cmd_data_path(struct wl12xx *wl, u8 channel, u8 enable);
-int wl12xx_cmd_join(struct wl12xx *wl, u8 bss_type, u8 dtim_interval,
+int wl1251_cmd_data_path(struct wl1251 *wl, u8 channel, bool enable);
+int wl1251_cmd_join(struct wl1251 *wl, u8 bss_type, u8 dtim_interval,
                    u16 beacon_interval, u8 wait);
-int wl12xx_cmd_ps_mode(struct wl12xx *wl, u8 ps_mode);
-int wl12xx_cmd_read_memory(struct wl12xx *wl, u32 addr, u32 len, void *answer);
-int wl12xx_cmd_template_set(struct wl12xx *wl, u16 cmd_id,
+int wl1251_cmd_ps_mode(struct wl1251 *wl, u8 ps_mode);
+int wl1251_cmd_read_memory(struct wl1251 *wl, u32 addr, void *answer,
+                          size_t len);
+int wl1251_cmd_template_set(struct wl1251 *wl, u16 cmd_id,
                            void *buf, size_t buf_len);
 
 /* unit ms */
-#define WL12XX_COMMAND_TIMEOUT 2000
-
-#define WL12XX_MAX_TEMPLATE_SIZE 300
+#define WL1251_COMMAND_TIMEOUT 2000
 
-struct wl12xx_cmd_packet_template {
-       __le16 size;
-       u8 template[WL12XX_MAX_TEMPLATE_SIZE];
-} __attribute__ ((packed));
-
-enum wl12xx_commands {
+enum wl1251_commands {
        CMD_RESET           = 0,
        CMD_INTERROGATE     = 1,    /*use this to read information elements*/
        CMD_CONFIGURE       = 2,    /*use this to write information elements*/
@@ -100,9 +95,15 @@ enum wl12xx_commands {
 
 #define MAX_CMD_PARAMS 572
 
-struct  wl12xx_command {
+struct wl1251_cmd_header {
        u16 id;
        u16 status;
+       /* payload */
+       u8 data[0];
+} __attribute__ ((packed));
+
+struct  wl1251_command {
+       struct wl1251_cmd_header header;
        u8  parameters[MAX_CMD_PARAMS];
 };
 
@@ -144,6 +145,8 @@ enum {
 #define MAX_READ_SIZE 256
 
 struct cmd_read_write_memory {
+       struct wl1251_cmd_header header;
+
        /* The address of the memory to read from or write to.*/
        u32 addr;
 
@@ -211,6 +214,8 @@ struct basic_scan_channel_parameters {
 #define SCAN_MAX_NUM_OF_CHANNELS 16
 
 struct cmd_scan {
+       struct wl1251_cmd_header header;
+
        struct basic_scan_parameters params;
        struct basic_scan_channel_parameters channels[SCAN_MAX_NUM_OF_CHANNELS];
 } __attribute__ ((packed));
@@ -227,6 +232,8 @@ enum {
 
 
 struct cmd_join {
+       struct wl1251_cmd_header header;
+
        u32 bssid_lsb;
        u16 bssid_msb;
        u16 beacon_interval; /* in TBTTs */
@@ -261,5 +268,140 @@ struct cmd_join {
        u8 reserved;
 } __attribute__ ((packed));
 
+struct cmd_enabledisable_path {
+       struct wl1251_cmd_header header;
+
+       u8 channel;
+       u8 padding[3];
+} __attribute__ ((packed));
+
+#define WL1251_MAX_TEMPLATE_SIZE 300
+
+struct wl1251_cmd_packet_template {
+       struct wl1251_cmd_header header;
+
+       __le16 size;
+       u8 data[0];
+} __attribute__ ((packed));
+
+#define TIM_ELE_ID    5
+#define PARTIAL_VBM_MAX    251
+
+struct wl1251_tim {
+       u8 identity;
+       u8 length;
+       u8 dtim_count;
+       u8 dtim_period;
+       u8 bitmap_ctrl;
+       u8 pvb_field[PARTIAL_VBM_MAX]; /* Partial Virtual Bitmap */
+} __attribute__ ((packed));
+
+/* Virtual Bit Map update */
+struct wl1251_cmd_vbm_update {
+       struct wl1251_cmd_header header;
+       __le16 len;
+       u8  padding[2];
+       struct wl1251_tim tim;
+} __attribute__ ((packed));
+
+enum wl1251_cmd_ps_mode {
+       STATION_ACTIVE_MODE,
+       STATION_POWER_SAVE_MODE
+};
+
+struct wl1251_cmd_ps_params {
+       struct wl1251_cmd_header header;
+
+       u8 ps_mode; /* STATION_* */
+       u8 send_null_data; /* Do we have to send NULL data packet ? */
+       u8 retries; /* Number of retires for the initial NULL data packet */
+
+        /*
+         * TUs during which the target stays awake after switching
+         * to power save mode.
+         */
+       u8 hang_over_period;
+       u16 null_data_rate;
+       u8 pad[2];
+} __attribute__ ((packed));
+
+struct wl1251_cmd_trigger_scan_to {
+       struct wl1251_cmd_header header;
+
+       u32 timeout;
+};
+
+/* HW encryption keys */
+#define NUM_ACCESS_CATEGORIES_COPY 4
+#define MAX_KEY_SIZE 32
+
+/* When set, disable HW encryption */
+#define DF_ENCRYPTION_DISABLE      0x01
+/* When set, disable HW decryption */
+#define DF_SNIFF_MODE_ENABLE       0x80
+
+enum wl1251_cmd_key_action {
+       KEY_ADD_OR_REPLACE = 1,
+       KEY_REMOVE         = 2,
+       KEY_SET_ID         = 3,
+       MAX_KEY_ACTION     = 0xffff,
+};
+
+enum wl1251_cmd_key_type {
+       KEY_WEP_DEFAULT       = 0,
+       KEY_WEP_ADDR          = 1,
+       KEY_AES_GROUP         = 4,
+       KEY_AES_PAIRWISE      = 5,
+       KEY_WEP_GROUP         = 6,
+       KEY_TKIP_MIC_GROUP    = 10,
+       KEY_TKIP_MIC_PAIRWISE = 11,
+};
+
+/*
+ *
+ * key_type_e   key size    key format
+ * ----------   ---------   ----------
+ * 0x00         5, 13, 29   Key data
+ * 0x01         5, 13, 29   Key data
+ * 0x04         16          16 bytes of key data
+ * 0x05         16          16 bytes of key data
+ * 0x0a         32          16 bytes of TKIP key data
+ *                          8 bytes of RX MIC key data
+ *                          8 bytes of TX MIC key data
+ * 0x0b         32          16 bytes of TKIP key data
+ *                          8 bytes of RX MIC key data
+ *                          8 bytes of TX MIC key data
+ *
+ */
+
+struct wl1251_cmd_set_keys {
+       struct wl1251_cmd_header header;
+
+       /* Ignored for default WEP key */
+       u8 addr[ETH_ALEN];
+
+       /* key_action_e */
+       u16 key_action;
+
+       u16 reserved_1;
+
+       /* key size in bytes */
+       u8 key_size;
+
+       /* key_type_e */
+       u8 key_type;
+       u8 ssid_profile;
+
+       /*
+        * TKIP, AES: frame's key id field.
+        * For WEP default key: key id;
+        */
+       u8 id;
+       u8 reserved_2[6];
+       u8 key[MAX_KEY_SIZE];
+       u16 ac_seq_num16[NUM_ACCESS_CATEGORIES_COPY];
+       u32 ac_seq_num32[NUM_ACCESS_CATEGORIES_COPY];
+} __attribute__ ((packed));
+
 
-#endif /* __WL12XX_CMD_H__ */
+#endif /* __WL1251_CMD_H__ */
similarity index 92%
rename from drivers/net/wireless/wl12xx/debugfs.c
rename to drivers/net/wireless/wl12xx/wl1251_debugfs.c
index cdb368c..a007230 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * This file is part of wl12xx
+ * This file is part of wl1251
  *
  * Copyright (C) 2009 Nokia Corporation
  *
  *
  */
 
-#include "debugfs.h"
+#include "wl1251_debugfs.h"
 
 #include <linux/skbuff.h>
 
-#include "wl12xx.h"
-#include "acx.h"
+#include "wl1251.h"
+#include "wl1251_acx.h"
+#include "wl1251_ps.h"
 
 /* ms */
-#define WL12XX_DEBUGFS_STATS_LIFETIME 1000
+#define WL1251_DEBUGFS_STATS_LIFETIME 1000
 
 /* debugfs macros idea from mac80211 */
 
@@ -37,7 +38,7 @@
 static ssize_t name## _read(struct file *file, char __user *userbuf,   \
                            size_t count, loff_t *ppos)                 \
 {                                                                      \
-       struct wl12xx *wl = file->private_data;                         \
+       struct wl1251 *wl = file->private_data;                         \
        char buf[buflen];                                               \
        int res;                                                        \
                                                                        \
@@ -47,7 +48,7 @@ static ssize_t name## _read(struct file *file, char __user *userbuf,  \
                                                                        \
 static const struct file_operations name## _ops = {                    \
        .read = name## _read,                                           \
-       .open = wl12xx_open_file_generic,                               \
+       .open = wl1251_open_file_generic,                               \
 };
 
 #define DEBUGFS_ADD(name, parent)                                      \
@@ -70,11 +71,11 @@ static ssize_t sub## _ ##name## _read(struct file *file,            \
                                      char __user *userbuf,             \
                                      size_t count, loff_t *ppos)       \
 {                                                                      \
-       struct wl12xx *wl = file->private_data;                         \
+       struct wl1251 *wl = file->private_data;                         \
        char buf[buflen];                                               \
        int res;                                                        \
                                                                        \
-       wl12xx_debugfs_update_stats(wl);                                \
+       wl1251_debugfs_update_stats(wl);                                \
                                                                        \
        res = scnprintf(buf, buflen, fmt "\n",                          \
                        wl->stats.fw_stats->sub.name);                  \
@@ -83,7 +84,7 @@ static ssize_t sub## _ ##name## _read(struct file *file,              \
                                                                        \
 static const struct file_operations sub## _ ##name## _ops = {          \
        .read = sub## _ ##name## _read,                                 \
-       .open = wl12xx_open_file_generic,                               \
+       .open = wl1251_open_file_generic,                               \
 };
 
 #define DEBUGFS_FWSTATS_ADD(sub, name)                         \
@@ -92,21 +93,30 @@ static const struct file_operations sub## _ ##name## _ops = {               \
 #define DEBUGFS_FWSTATS_DEL(sub, name)                         \
        DEBUGFS_DEL(sub## _ ##name)
 
-static void wl12xx_debugfs_update_stats(struct wl12xx *wl)
+static void wl1251_debugfs_update_stats(struct wl1251 *wl)
 {
+       int ret;
+
        mutex_lock(&wl->mutex);
 
-       if (wl->state == WL12XX_STATE_ON &&
+       ret = wl1251_ps_elp_wakeup(wl);
+       if (ret < 0)
+               goto out;
+
+       if (wl->state == WL1251_STATE_ON &&
            time_after(jiffies, wl->stats.fw_stats_update +
-                      msecs_to_jiffies(WL12XX_DEBUGFS_STATS_LIFETIME))) {
-               wl12xx_acx_statistics(wl, wl->stats.fw_stats);
+                      msecs_to_jiffies(WL1251_DEBUGFS_STATS_LIFETIME))) {
+               wl1251_acx_statistics(wl, wl->stats.fw_stats);
                wl->stats.fw_stats_update = jiffies;
        }
 
+       wl1251_ps_elp_sleep(wl);
+
+out:
        mutex_unlock(&wl->mutex);
 }
 
-static int wl12xx_open_file_generic(struct inode *inode, struct file *file)
+static int wl1251_open_file_generic(struct inode *inode, struct file *file)
 {
        file->private_data = inode->i_private;
        return 0;
@@ -211,7 +221,7 @@ DEBUGFS_READONLY_FILE(excessive_retries, 20, "%u",
 static ssize_t tx_queue_len_read(struct file *file, char __user *userbuf,
                                 size_t count, loff_t *ppos)
 {
-       struct wl12xx *wl = file->private_data;
+       struct wl1251 *wl = file->private_data;
        u32 queue_len;
        char buf[20];
        int res;
@@ -224,10 +234,10 @@ static ssize_t tx_queue_len_read(struct file *file, char __user *userbuf,
 
 static const struct file_operations tx_queue_len_ops = {
        .read = tx_queue_len_read,
-       .open = wl12xx_open_file_generic,
+       .open = wl1251_open_file_generic,
 };
 
-static void wl12xx_debugfs_delete_files(struct wl12xx *wl)
+static void wl1251_debugfs_delete_files(struct wl1251 *wl)
 {
        DEBUGFS_FWSTATS_DEL(tx, internal_desc_overflow);
 
@@ -325,7 +335,7 @@ static void wl12xx_debugfs_delete_files(struct wl12xx *wl)
        DEBUGFS_DEL(excessive_retries);
 }
 
-static int wl12xx_debugfs_add_files(struct wl12xx *wl)
+static int wl1251_debugfs_add_files(struct wl1251 *wl)
 {
        int ret = 0;
 
@@ -426,19 +436,19 @@ static int wl12xx_debugfs_add_files(struct wl12xx *wl)
 
 out:
        if (ret < 0)
-               wl12xx_debugfs_delete_files(wl);
+               wl1251_debugfs_delete_files(wl);
 
        return ret;
 }
 
-void wl12xx_debugfs_reset(struct wl12xx *wl)
+void wl1251_debugfs_reset(struct wl1251 *wl)
 {
        memset(wl->stats.fw_stats, 0, sizeof(*wl->stats.fw_stats));
        wl->stats.retry_count = 0;
        wl->stats.excessive_retries = 0;
 }
 
-int wl12xx_debugfs_init(struct wl12xx *wl)
+int wl1251_debugfs_init(struct wl1251 *wl)
 {
        int ret;
 
@@ -469,7 +479,7 @@ int wl12xx_debugfs_init(struct wl12xx *wl)
 
        wl->stats.fw_stats_update = jiffies;
 
-       ret = wl12xx_debugfs_add_files(wl);
+       ret = wl1251_debugfs_add_files(wl);
 
        if (ret < 0)
                goto err_file;
@@ -492,9 +502,9 @@ err:
        return ret;
 }
 
-void wl12xx_debugfs_exit(struct wl12xx *wl)
+void wl1251_debugfs_exit(struct wl1251 *wl)
 {
-       wl12xx_debugfs_delete_files(wl);
+       wl1251_debugfs_delete_files(wl);
 
        kfree(wl->stats.fw_stats);
        wl->stats.fw_stats = NULL;
similarity index 74%
rename from drivers/net/wireless/wl12xx/debugfs.h
rename to drivers/net/wireless/wl12xx/wl1251_debugfs.h
index 562cdcb..6dc3d08 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * This file is part of wl12xx
+ * This file is part of wl1251
  *
  * Copyright (C) 2009 Nokia Corporation
  *
  *
  */
 
-#ifndef WL12XX_DEBUGFS_H
-#define WL12XX_DEBUGFS_H
+#ifndef WL1251_DEBUGFS_H
+#define WL1251_DEBUGFS_H
 
-#include "wl12xx.h"
+#include "wl1251.h"
 
-int wl12xx_debugfs_init(struct wl12xx *wl);
-void wl12xx_debugfs_exit(struct wl12xx *wl);
-void wl12xx_debugfs_reset(struct wl12xx *wl);
+int wl1251_debugfs_init(struct wl1251 *wl);
+void wl1251_debugfs_exit(struct wl1251 *wl);
+void wl1251_debugfs_reset(struct wl1251 *wl);
 
-#endif /* WL12XX_DEBUGFS_H */
+#endif /* WL1251_DEBUGFS_H */
similarity index 59%
rename from drivers/net/wireless/wl12xx/event.c
rename to drivers/net/wireless/wl12xx/wl1251_event.c
index 99529ca..1a0a0bc 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * This file is part of wl12xx
+ * This file is part of wl1251
  *
  * Copyright (c) 1998-2007 Texas Instruments Incorporated
  * Copyright (C) 2008 Nokia Corporation
  *
  */
 
-#include "wl12xx.h"
+#include "wl1251.h"
 #include "reg.h"
-#include "spi.h"
-#include "event.h"
-#include "ps.h"
+#include "wl1251_spi.h"
+#include "wl1251_event.h"
+#include "wl1251_ps.h"
 
-static int wl12xx_event_scan_complete(struct wl12xx *wl,
+static int wl1251_event_scan_complete(struct wl1251 *wl,
                                      struct event_mailbox *mbox)
 {
-       wl12xx_debug(DEBUG_EVENT, "status: 0x%x, channels: %d",
+       wl1251_debug(DEBUG_EVENT, "status: 0x%x, channels: %d",
                     mbox->scheduled_scan_status,
                     mbox->scheduled_scan_channels);
 
@@ -45,34 +45,34 @@ static int wl12xx_event_scan_complete(struct wl12xx *wl,
        return 0;
 }
 
-static void wl12xx_event_mbox_dump(struct event_mailbox *mbox)
+static void wl1251_event_mbox_dump(struct event_mailbox *mbox)
 {
-       wl12xx_debug(DEBUG_EVENT, "MBOX DUMP:");
-       wl12xx_debug(DEBUG_EVENT, "\tvector: 0x%x", mbox->events_vector);
-       wl12xx_debug(DEBUG_EVENT, "\tmask: 0x%x", mbox->events_mask);
+       wl1251_debug(DEBUG_EVENT, "MBOX DUMP:");
+       wl1251_debug(DEBUG_EVENT, "\tvector: 0x%x", mbox->events_vector);
+       wl1251_debug(DEBUG_EVENT, "\tmask: 0x%x", mbox->events_mask);
 }
 
-static int wl12xx_event_process(struct wl12xx *wl, struct event_mailbox *mbox)
+static int wl1251_event_process(struct wl1251 *wl, struct event_mailbox *mbox)
 {
        int ret;
        u32 vector;
 
-       wl12xx_event_mbox_dump(mbox);
+       wl1251_event_mbox_dump(mbox);
 
        vector = mbox->events_vector & ~(mbox->events_mask);
-       wl12xx_debug(DEBUG_EVENT, "vector: 0x%x", vector);
+       wl1251_debug(DEBUG_EVENT, "vector: 0x%x", vector);
 
        if (vector & SCAN_COMPLETE_EVENT_ID) {
-               ret = wl12xx_event_scan_complete(wl, mbox);
+               ret = wl1251_event_scan_complete(wl, mbox);
                if (ret < 0)
                        return ret;
        }
 
        if (vector & BSS_LOSE_EVENT_ID) {
-               wl12xx_debug(DEBUG_EVENT, "BSS_LOSE_EVENT");
+               wl1251_debug(DEBUG_EVENT, "BSS_LOSE_EVENT");
 
                if (wl->psm_requested && wl->psm) {
-                       ret = wl12xx_ps_set_mode(wl, STATION_ACTIVE_MODE);
+                       ret = wl1251_ps_set_mode(wl, STATION_ACTIVE_MODE);
                        if (ret < 0)
                                return ret;
                }
@@ -81,47 +81,47 @@ static int wl12xx_event_process(struct wl12xx *wl, struct event_mailbox *mbox)
        return 0;
 }
 
-int wl12xx_event_unmask(struct wl12xx *wl)
+int wl1251_event_unmask(struct wl1251 *wl)
 {
        int ret;
 
-       ret = wl12xx_acx_event_mbox_mask(wl, ~(wl->event_mask));
+       ret = wl1251_acx_event_mbox_mask(wl, ~(wl->event_mask));
        if (ret < 0)
                return ret;
 
        return 0;
 }
 
-void wl12xx_event_mbox_config(struct wl12xx *wl)
+void wl1251_event_mbox_config(struct wl1251 *wl)
 {
-       wl->mbox_ptr[0] = wl12xx_reg_read32(wl, REG_EVENT_MAILBOX_PTR);
+       wl->mbox_ptr[0] = wl1251_reg_read32(wl, REG_EVENT_MAILBOX_PTR);
        wl->mbox_ptr[1] = wl->mbox_ptr[0] + sizeof(struct event_mailbox);
 
-       wl12xx_debug(DEBUG_EVENT, "MBOX ptrs: 0x%x 0x%x",
+       wl1251_debug(DEBUG_EVENT, "MBOX ptrs: 0x%x 0x%x",
                     wl->mbox_ptr[0], wl->mbox_ptr[1]);
 }
 
-int wl12xx_event_handle(struct wl12xx *wl, u8 mbox_num)
+int wl1251_event_handle(struct wl1251 *wl, u8 mbox_num)
 {
        struct event_mailbox mbox;
        int ret;
 
-       wl12xx_debug(DEBUG_EVENT, "EVENT on mbox %d", mbox_num);
+       wl1251_debug(DEBUG_EVENT, "EVENT on mbox %d", mbox_num);
 
        if (mbox_num > 1)
                return -EINVAL;
 
        /* first we read the mbox descriptor */
-       wl12xx_spi_mem_read(wl, wl->mbox_ptr[mbox_num], &mbox,
+       wl1251_spi_mem_read(wl, wl->mbox_ptr[mbox_num], &mbox,
                            sizeof(struct event_mailbox));
 
        /* process the descriptor */
-       ret = wl12xx_event_process(wl, &mbox);
+       ret = wl1251_event_process(wl, &mbox);
        if (ret < 0)
                return ret;
 
        /* then we let the firmware know it can go on...*/
-       wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_EVENT_ACK);
+       wl1251_reg_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_EVENT_ACK);
 
        return 0;
 }
similarity index 94%
rename from drivers/net/wireless/wl12xx/event.h
rename to drivers/net/wireless/wl12xx/wl1251_event.h
index 1f4c2f7..be0ac54 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * This file is part of wl12xx
+ * This file is part of wl1251
  *
  * Copyright (c) 1998-2007 Texas Instruments Incorporated
  * Copyright (C) 2008 Nokia Corporation
@@ -22,8 +22,8 @@
  *
  */
 
-#ifndef __WL12XX_EVENT_H__
-#define __WL12XX_EVENT_H__
+#ifndef __WL1251_EVENT_H__
+#define __WL1251_EVENT_H__
 
 /*
  * Mbox events
@@ -114,8 +114,8 @@ struct event_mailbox {
        u8 padding[19];
 } __attribute__ ((packed));
 
-int wl12xx_event_unmask(struct wl12xx *wl);
-void wl12xx_event_mbox_config(struct wl12xx *wl);
-int wl12xx_event_handle(struct wl12xx *wl, u8 mbox);
+int wl1251_event_unmask(struct wl1251 *wl);
+void wl1251_event_mbox_config(struct wl1251 *wl);
+int wl1251_event_handle(struct wl1251 *wl, u8 mbox);
 
 #endif
similarity index 55%
rename from drivers/net/wireless/wl12xx/init.c
rename to drivers/net/wireless/wl12xx/wl1251_init.c
index 2a573a6..df6c60f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * This file is part of wl12xx
+ * This file is part of wl1251
  *
  * Copyright (C) 2009 Nokia Corporation
  *
 #include <linux/kernel.h>
 #include <linux/module.h>
 
-#include "init.h"
+#include "wl1251_init.h"
 #include "wl12xx_80211.h"
-#include "acx.h"
-#include "cmd.h"
+#include "wl1251_acx.h"
+#include "wl1251_cmd.h"
 
-int wl12xx_hw_init_hwenc_config(struct wl12xx *wl)
+int wl1251_hw_init_hwenc_config(struct wl1251 *wl)
 {
        int ret;
 
-       ret = wl12xx_acx_feature_cfg(wl);
+       ret = wl1251_acx_feature_cfg(wl);
        if (ret < 0) {
-               wl12xx_warning("couldn't set feature config");
+               wl1251_warning("couldn't set feature config");
                return ret;
        }
 
-       ret = wl12xx_acx_default_key(wl, wl->default_key);
+       ret = wl1251_acx_default_key(wl, wl->default_key);
        if (ret < 0) {
-               wl12xx_warning("couldn't set default key");
+               wl1251_warning("couldn't set default key");
                return ret;
        }
 
        return 0;
 }
 
-int wl12xx_hw_init_templates_config(struct wl12xx *wl)
+int wl1251_hw_init_templates_config(struct wl1251 *wl)
 {
        int ret;
        u8 partial_vbm[PARTIAL_VBM_MAX];
 
        /* send empty templates for fw memory reservation */
-       ret = wl12xx_cmd_template_set(wl, CMD_PROBE_REQ, NULL,
+       ret = wl1251_cmd_template_set(wl, CMD_PROBE_REQ, NULL,
                                      sizeof(struct wl12xx_probe_req_template));
        if (ret < 0)
                return ret;
 
-       ret = wl12xx_cmd_template_set(wl, CMD_NULL_DATA, NULL,
+       ret = wl1251_cmd_template_set(wl, CMD_NULL_DATA, NULL,
                                      sizeof(struct wl12xx_null_data_template));
        if (ret < 0)
                return ret;
 
-       ret = wl12xx_cmd_template_set(wl, CMD_PS_POLL, NULL,
+       ret = wl1251_cmd_template_set(wl, CMD_PS_POLL, NULL,
                                      sizeof(struct wl12xx_ps_poll_template));
        if (ret < 0)
                return ret;
 
-       ret = wl12xx_cmd_template_set(wl, CMD_QOS_NULL_DATA, NULL,
+       ret = wl1251_cmd_template_set(wl, CMD_QOS_NULL_DATA, NULL,
                                      sizeof
                                      (struct wl12xx_qos_null_data_template));
        if (ret < 0)
                return ret;
 
-       ret = wl12xx_cmd_template_set(wl, CMD_PROBE_RESP, NULL,
+       ret = wl1251_cmd_template_set(wl, CMD_PROBE_RESP, NULL,
                                      sizeof
                                      (struct wl12xx_probe_resp_template));
        if (ret < 0)
                return ret;
 
-       ret = wl12xx_cmd_template_set(wl, CMD_BEACON, NULL,
+       ret = wl1251_cmd_template_set(wl, CMD_BEACON, NULL,
                                      sizeof
                                      (struct wl12xx_beacon_template));
        if (ret < 0)
@@ -89,112 +89,112 @@ int wl12xx_hw_init_templates_config(struct wl12xx *wl)
 
        /* tim templates, first reserve space then allocate an empty one */
        memset(partial_vbm, 0, PARTIAL_VBM_MAX);
-       ret = wl12xx_cmd_vbm(wl, TIM_ELE_ID, partial_vbm, PARTIAL_VBM_MAX, 0);
+       ret = wl1251_cmd_vbm(wl, TIM_ELE_ID, partial_vbm, PARTIAL_VBM_MAX, 0);
        if (ret < 0)
                return ret;
 
-       ret = wl12xx_cmd_vbm(wl, TIM_ELE_ID, partial_vbm, 1, 0);
+       ret = wl1251_cmd_vbm(wl, TIM_ELE_ID, partial_vbm, 1, 0);
        if (ret < 0)
                return ret;
 
        return 0;
 }
 
-int wl12xx_hw_init_rx_config(struct wl12xx *wl, u32 config, u32 filter)
+int wl1251_hw_init_rx_config(struct wl1251 *wl, u32 config, u32 filter)
 {
        int ret;
 
-       ret = wl12xx_acx_rx_msdu_life_time(wl, RX_MSDU_LIFETIME_DEF);
+       ret = wl1251_acx_rx_msdu_life_time(wl, RX_MSDU_LIFETIME_DEF);
        if (ret < 0)
                return ret;
 
-       ret = wl12xx_acx_rx_config(wl, config, filter);
+       ret = wl1251_acx_rx_config(wl, config, filter);
        if (ret < 0)
                return ret;
 
        return 0;
 }
 
-int wl12xx_hw_init_phy_config(struct wl12xx *wl)
+int wl1251_hw_init_phy_config(struct wl1251 *wl)
 {
        int ret;
 
-       ret = wl12xx_acx_pd_threshold(wl);
+       ret = wl1251_acx_pd_threshold(wl);
        if (ret < 0)
                return ret;
 
-       ret = wl12xx_acx_slot(wl, DEFAULT_SLOT_TIME);
+       ret = wl1251_acx_slot(wl, DEFAULT_SLOT_TIME);
        if (ret < 0)
                return ret;
 
-       ret = wl12xx_acx_group_address_tbl(wl);
+       ret = wl1251_acx_group_address_tbl(wl);
        if (ret < 0)
                return ret;
 
-       ret = wl12xx_acx_service_period_timeout(wl);
+       ret = wl1251_acx_service_period_timeout(wl);
        if (ret < 0)
                return ret;
 
-       ret = wl12xx_acx_rts_threshold(wl, RTS_THRESHOLD_DEF);
+       ret = wl1251_acx_rts_threshold(wl, RTS_THRESHOLD_DEF);
        if (ret < 0)
                return ret;
 
        return 0;
 }
 
-int wl12xx_hw_init_beacon_filter(struct wl12xx *wl)
+int wl1251_hw_init_beacon_filter(struct wl1251 *wl)
 {
        int ret;
 
-       ret = wl12xx_acx_beacon_filter_opt(wl);
+       ret = wl1251_acx_beacon_filter_opt(wl);
        if (ret < 0)
                return ret;
 
-       ret = wl12xx_acx_beacon_filter_table(wl);
+       ret = wl1251_acx_beacon_filter_table(wl);
        if (ret < 0)
                return ret;
 
        return 0;
 }
 
-int wl12xx_hw_init_pta(struct wl12xx *wl)
+int wl1251_hw_init_pta(struct wl1251 *wl)
 {
        int ret;
 
-       ret = wl12xx_acx_sg_enable(wl);
+       ret = wl1251_acx_sg_enable(wl);
        if (ret < 0)
                return ret;
 
-       ret = wl12xx_acx_sg_cfg(wl);
+       ret = wl1251_acx_sg_cfg(wl);
        if (ret < 0)
                return ret;
 
        return 0;
 }
 
-int wl12xx_hw_init_energy_detection(struct wl12xx *wl)
+int wl1251_hw_init_energy_detection(struct wl1251 *wl)
 {
        int ret;
 
-       ret = wl12xx_acx_cca_threshold(wl);
+       ret = wl1251_acx_cca_threshold(wl);
        if (ret < 0)
                return ret;
 
        return 0;
 }
 
-int wl12xx_hw_init_beacon_broadcast(struct wl12xx *wl)
+int wl1251_hw_init_beacon_broadcast(struct wl1251 *wl)
 {
        int ret;
 
-       ret = wl12xx_acx_bcn_dtim_options(wl);
+       ret = wl1251_acx_bcn_dtim_options(wl);
        if (ret < 0)
                return ret;
 
        return 0;
 }
 
-int wl12xx_hw_init_power_auth(struct wl12xx *wl)
+int wl1251_hw_init_power_auth(struct wl1251 *wl)
 {
-       return wl12xx_acx_sleep_auth(wl, WL12XX_PSM_CAM);
+       return wl1251_acx_sleep_auth(wl, WL1251_PSM_CAM);
 }
similarity index 55%
rename from drivers/net/wireless/wl12xx/init.h
rename to drivers/net/wireless/wl12xx/wl1251_init.h
index c8b6cd0..8596188 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * This file is part of wl12xx
+ * This file is part of wl1251
  *
  * Copyright (C) 2009 Nokia Corporation
  *
  *
  */
 
-#ifndef __WL12XX_INIT_H__
-#define __WL12XX_INIT_H__
+#ifndef __WL1251_INIT_H__
+#define __WL1251_INIT_H__
 
-#include "wl12xx.h"
+#include "wl1251.h"
 
-int wl12xx_hw_init_hwenc_config(struct wl12xx *wl);
-int wl12xx_hw_init_templates_config(struct wl12xx *wl);
-int wl12xx_hw_init_mem_config(struct wl12xx *wl);
-int wl12xx_hw_init_rx_config(struct wl12xx *wl, u32 config, u32 filter);
-int wl12xx_hw_init_phy_config(struct wl12xx *wl);
-int wl12xx_hw_init_beacon_filter(struct wl12xx *wl);
-int wl12xx_hw_init_pta(struct wl12xx *wl);
-int wl12xx_hw_init_energy_detection(struct wl12xx *wl);
-int wl12xx_hw_init_beacon_broadcast(struct wl12xx *wl);
-int wl12xx_hw_init_power_auth(struct wl12xx *wl);
+int wl1251_hw_init_hwenc_config(struct wl1251 *wl);
+int wl1251_hw_init_templates_config(struct wl1251 *wl);
+int wl1251_hw_init_rx_config(struct wl1251 *wl, u32 config, u32 filter);
+int wl1251_hw_init_phy_config(struct wl1251 *wl);
+int wl1251_hw_init_beacon_filter(struct wl1251 *wl);
+int wl1251_hw_init_pta(struct wl1251 *wl);
+int wl1251_hw_init_energy_detection(struct wl1251 *wl);
+int wl1251_hw_init_beacon_broadcast(struct wl1251 *wl);
+int wl1251_hw_init_power_auth(struct wl1251 *wl);
 
 #endif
similarity index 60%
rename from drivers/net/wireless/wl12xx/main.c
rename to drivers/net/wireless/wl12xx/wl1251_main.c
index 603d611..cf5e054 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * This file is part of wl12xx
+ * This file is part of wl1251
  *
  * Copyright (C) 2008-2009 Nokia Corporation
  *
 #include <linux/etherdevice.h>
 #include <linux/spi/wl12xx.h>
 
-#include "wl12xx.h"
+#include "wl1251.h"
 #include "wl12xx_80211.h"
 #include "reg.h"
-#include "wl1251.h"
-#include "spi.h"
-#include "event.h"
-#include "tx.h"
-#include "rx.h"
-#include "ps.h"
-#include "init.h"
-#include "debugfs.h"
-
-static void wl12xx_disable_interrupts(struct wl12xx *wl)
+#include "wl1251_ops.h"
+#include "wl1251_spi.h"
+#include "wl1251_event.h"
+#include "wl1251_tx.h"
+#include "wl1251_rx.h"
+#include "wl1251_ps.h"
+#include "wl1251_init.h"
+#include "wl1251_debugfs.h"
+
+static void wl1251_disable_interrupts(struct wl1251 *wl)
 {
        disable_irq(wl->irq);
 }
 
-static void wl12xx_power_off(struct wl12xx *wl)
+static void wl1251_power_off(struct wl1251 *wl)
 {
        wl->set_power(false);
 }
 
-static void wl12xx_power_on(struct wl12xx *wl)
+static void wl1251_power_on(struct wl1251 *wl)
 {
        wl->set_power(true);
 }
 
-static irqreturn_t wl12xx_irq(int irq, void *cookie)
+static irqreturn_t wl1251_irq(int irq, void *cookie)
 {
-       struct wl12xx *wl;
+       struct wl1251 *wl;
 
-       wl12xx_debug(DEBUG_IRQ, "IRQ");
+       wl1251_debug(DEBUG_IRQ, "IRQ");
 
        wl = cookie;
 
@@ -71,7 +71,7 @@ static irqreturn_t wl12xx_irq(int irq, void *cookie)
        return IRQ_HANDLED;
 }
 
-static int wl12xx_fetch_firmware(struct wl12xx *wl)
+static int wl1251_fetch_firmware(struct wl1251 *wl)
 {
        const struct firmware *fw;
        int ret;
@@ -79,12 +79,12 @@ static int wl12xx_fetch_firmware(struct wl12xx *wl)
        ret = request_firmware(&fw, wl->chip.fw_filename, &wl->spi->dev);
 
        if (ret < 0) {
-               wl12xx_error("could not get firmware: %d", ret);
+               wl1251_error("could not get firmware: %d", ret);
                return ret;
        }
 
        if (fw->size % 4) {
-               wl12xx_error("firmware size is not multiple of 32 bits: %zu",
+               wl1251_error("firmware size is not multiple of 32 bits: %zu",
                             fw->size);
                ret = -EILSEQ;
                goto out;
@@ -94,7 +94,7 @@ static int wl12xx_fetch_firmware(struct wl12xx *wl)
        wl->fw = kmalloc(wl->fw_len, GFP_KERNEL);
 
        if (!wl->fw) {
-               wl12xx_error("could not allocate memory for the firmware");
+               wl1251_error("could not allocate memory for the firmware");
                ret = -ENOMEM;
                goto out;
        }
@@ -109,7 +109,7 @@ out:
        return ret;
 }
 
-static int wl12xx_fetch_nvs(struct wl12xx *wl)
+static int wl1251_fetch_nvs(struct wl1251 *wl)
 {
        const struct firmware *fw;
        int ret;
@@ -117,12 +117,12 @@ static int wl12xx_fetch_nvs(struct wl12xx *wl)
        ret = request_firmware(&fw, wl->chip.nvs_filename, &wl->spi->dev);
 
        if (ret < 0) {
-               wl12xx_error("could not get nvs file: %d", ret);
+               wl1251_error("could not get nvs file: %d", ret);
                return ret;
        }
 
        if (fw->size % 4) {
-               wl12xx_error("nvs size is not multiple of 32 bits: %zu",
+               wl1251_error("nvs size is not multiple of 32 bits: %zu",
                             fw->size);
                ret = -EILSEQ;
                goto out;
@@ -132,7 +132,7 @@ static int wl12xx_fetch_nvs(struct wl12xx *wl)
        wl->nvs = kmalloc(wl->nvs_len, GFP_KERNEL);
 
        if (!wl->nvs) {
-               wl12xx_error("could not allocate memory for the nvs file");
+               wl1251_error("could not allocate memory for the nvs file");
                ret = -ENOMEM;
                goto out;
        }
@@ -147,74 +147,70 @@ out:
        return ret;
 }
 
-static void wl12xx_fw_wakeup(struct wl12xx *wl)
+static void wl1251_fw_wakeup(struct wl1251 *wl)
 {
        u32 elp_reg;
 
        elp_reg = ELPCTRL_WAKE_UP;
-       wl12xx_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
-       elp_reg = wl12xx_read32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR);
+       wl1251_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
+       elp_reg = wl1251_read32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR);
 
-       if (!(elp_reg & ELPCTRL_WLAN_READY)) {
-               wl12xx_warning("WLAN not ready");
-               elp_reg = ELPCTRL_WAKE_UP_WLAN_READY;
-               wl12xx_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
-       }
+       if (!(elp_reg & ELPCTRL_WLAN_READY))
+               wl1251_warning("WLAN not ready");
 }
 
-static int wl12xx_chip_wakeup(struct wl12xx *wl)
+static int wl1251_chip_wakeup(struct wl1251 *wl)
 {
        int ret = 0;
 
-       wl12xx_power_on(wl);
+       wl1251_power_on(wl);
        msleep(wl->chip.power_on_sleep);
-       wl12xx_spi_reset(wl);
-       wl12xx_spi_init(wl);
+       wl1251_spi_reset(wl);
+       wl1251_spi_init(wl);
 
        /* We don't need a real memory partition here, because we only want
         * to use the registers at this point. */
-       wl12xx_set_partition(wl,
+       wl1251_set_partition(wl,
                             0x00000000,
                             0x00000000,
                             REGISTERS_BASE,
                             REGISTERS_DOWN_SIZE);
 
        /* ELP module wake up */
-       wl12xx_fw_wakeup(wl);
+       wl1251_fw_wakeup(wl);
 
        /* whal_FwCtrl_BootSm() */
 
        /* 0. read chip id from CHIP_ID */
-       wl->chip.id = wl12xx_reg_read32(wl, CHIP_ID_B);
+       wl->chip.id = wl1251_reg_read32(wl, CHIP_ID_B);
 
        /* 1. check if chip id is valid */
 
        switch (wl->chip.id) {
        case CHIP_ID_1251_PG12:
-               wl12xx_debug(DEBUG_BOOT, "chip id 0x%x (1251 PG12)",
+               wl1251_debug(DEBUG_BOOT, "chip id 0x%x (1251 PG12)",
                             wl->chip.id);
 
                wl1251_setup(wl);
 
                break;
-       case CHIP_ID_1271_PG10:
        case CHIP_ID_1251_PG10:
        case CHIP_ID_1251_PG11:
        default:
-               wl12xx_error("unsupported chip id: 0x%x", wl->chip.id);
+               wl1251_error("unsupported chip id: 0x%x", wl->chip.id);
                ret = -ENODEV;
                goto out;
        }
 
        if (wl->fw == NULL) {
-               ret = wl12xx_fetch_firmware(wl);
+               ret = wl1251_fetch_firmware(wl);
                if (ret < 0)
                        goto out;
        }
 
        /* No NVS from netlink, try to get it from the filesystem */
        if (wl->nvs == NULL) {
-               ret = wl12xx_fetch_nvs(wl);
+               ret = wl1251_fetch_nvs(wl);
                if (ret < 0)
                        goto out;
        }
@@ -223,40 +219,50 @@ out:
        return ret;
 }
 
-static void wl12xx_filter_work(struct work_struct *work)
+static void wl1251_filter_work(struct work_struct *work)
 {
-       struct wl12xx *wl =
-               container_of(work, struct wl12xx, filter_work);
+       struct wl1251 *wl =
+               container_of(work, struct wl1251, filter_work);
        int ret;
 
        mutex_lock(&wl->mutex);
 
-       if (wl->state == WL12XX_STATE_OFF)
+       if (wl->state == WL1251_STATE_OFF)
                goto out;
 
-       ret = wl12xx_cmd_join(wl, wl->bss_type, 1, 100, 0);
+       ret = wl1251_ps_elp_wakeup(wl);
        if (ret < 0)
                goto out;
 
+       /* FIXME: replace the magic numbers with proper definitions */
+       ret = wl->chip.op_cmd_join(wl, wl->bss_type, 1, 100, 0);
+       if (ret < 0)
+               goto out_sleep;
+
+out_sleep:
+       wl1251_ps_elp_sleep(wl);
+
 out:
        mutex_unlock(&wl->mutex);
 }
 
-int wl12xx_plt_start(struct wl12xx *wl)
+int wl1251_plt_start(struct wl1251 *wl)
 {
        int ret;
 
-       wl12xx_notice("power up");
+       mutex_lock(&wl->mutex);
+
+       wl1251_notice("power up");
 
-       if (wl->state != WL12XX_STATE_OFF) {
-               wl12xx_error("cannot go into PLT state because not "
+       if (wl->state != WL1251_STATE_OFF) {
+               wl1251_error("cannot go into PLT state because not "
                             "in off state: %d", wl->state);
                return -EBUSY;
        }
 
-       wl->state = WL12XX_STATE_PLT;
+       wl->state = WL1251_STATE_PLT;
 
-       ret = wl12xx_chip_wakeup(wl);
+       ret = wl1251_chip_wakeup(wl);
        if (ret < 0)
                return ret;
 
@@ -264,7 +270,7 @@ int wl12xx_plt_start(struct wl12xx *wl)
        if (ret < 0)
                return ret;
 
-       wl12xx_notice("firmware booted in PLT mode (%s)", wl->chip.fw_ver);
+       wl1251_notice("firmware booted in PLT mode (%s)", wl->chip.fw_ver);
 
        ret = wl->chip.op_plt_init(wl);
        if (ret < 0)
@@ -273,38 +279,45 @@ int wl12xx_plt_start(struct wl12xx *wl)
        return 0;
 }
 
-int wl12xx_plt_stop(struct wl12xx *wl)
+int wl1251_plt_stop(struct wl1251 *wl)
 {
-       wl12xx_notice("power down");
+       mutex_lock(&wl->mutex);
+
+       wl1251_notice("power down");
 
-       if (wl->state != WL12XX_STATE_PLT) {
-               wl12xx_error("cannot power down because not in PLT "
+       if (wl->state != WL1251_STATE_PLT) {
+               wl1251_error("cannot power down because not in PLT "
                             "state: %d", wl->state);
                return -EBUSY;
        }
 
-       wl12xx_disable_interrupts(wl);
-       wl12xx_power_off(wl);
+       wl1251_disable_interrupts(wl);
+       wl1251_power_off(wl);
 
-       wl->state = WL12XX_STATE_OFF;
+       wl->state = WL1251_STATE_OFF;
 
        return 0;
 }
 
 
-static int wl12xx_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
+static int wl1251_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
 {
-       struct wl12xx *wl = hw->priv;
+       struct wl1251 *wl = hw->priv;
 
        skb_queue_tail(&wl->tx_queue, skb);
 
+       /*
+        * The chip specific setup must run before the first TX packet -
+        * before that, the tx_work will not be initialized!
+        */
+
        schedule_work(&wl->tx_work);
 
        /*
         * The workqueue is slow to process the tx_queue and we need stop
         * the queue here, otherwise the queue will get too long.
         */
-       if (skb_queue_len(&wl->tx_queue) >= WL12XX_TX_QUEUE_MAX_LENGTH) {
+       if (skb_queue_len(&wl->tx_queue) >= WL1251_TX_QUEUE_MAX_LENGTH) {
                ieee80211_stop_queues(wl->hw);
 
                /*
@@ -318,23 +331,23 @@ static int wl12xx_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
        return NETDEV_TX_OK;
 }
 
-static int wl12xx_op_start(struct ieee80211_hw *hw)
+static int wl1251_op_start(struct ieee80211_hw *hw)
 {
-       struct wl12xx *wl = hw->priv;
+       struct wl1251 *wl = hw->priv;
        int ret = 0;
 
-       wl12xx_debug(DEBUG_MAC80211, "mac80211 start");
+       wl1251_debug(DEBUG_MAC80211, "mac80211 start");
 
        mutex_lock(&wl->mutex);
 
-       if (wl->state != WL12XX_STATE_OFF) {
-               wl12xx_error("cannot start because not in off state: %d",
+       if (wl->state != WL1251_STATE_OFF) {
+               wl1251_error("cannot start because not in off state: %d",
                             wl->state);
                ret = -EBUSY;
                goto out;
        }
 
-       ret = wl12xx_chip_wakeup(wl);
+       ret = wl1251_chip_wakeup(wl);
        if (ret < 0)
                return ret;
 
@@ -346,34 +359,34 @@ static int wl12xx_op_start(struct ieee80211_hw *hw)
        if (ret < 0)
                goto out;
 
-       ret = wl12xx_acx_station_id(wl);
+       ret = wl1251_acx_station_id(wl);
        if (ret < 0)
                goto out;
 
-       wl->state = WL12XX_STATE_ON;
+       wl->state = WL1251_STATE_ON;
 
-       wl12xx_info("firmware booted (%s)", wl->chip.fw_ver);
+       wl1251_info("firmware booted (%s)", wl->chip.fw_ver);
 
 out:
        if (ret < 0)
-               wl12xx_power_off(wl);
+               wl1251_power_off(wl);
 
        mutex_unlock(&wl->mutex);
 
        return ret;
 }
 
-static void wl12xx_op_stop(struct ieee80211_hw *hw)
+static void wl1251_op_stop(struct ieee80211_hw *hw)
 {
-       struct wl12xx *wl = hw->priv;
+       struct wl1251 *wl = hw->priv;
 
-       wl12xx_info("down");
+       wl1251_info("down");
 
-       wl12xx_debug(DEBUG_MAC80211, "mac80211 stop");
+       wl1251_debug(DEBUG_MAC80211, "mac80211 stop");
 
        mutex_lock(&wl->mutex);
 
-       WARN_ON(wl->state != WL12XX_STATE_ON);
+       WARN_ON(wl->state != WL1251_STATE_ON);
 
        if (wl->scanning) {
                mutex_unlock(&wl->mutex);
@@ -382,9 +395,9 @@ static void wl12xx_op_stop(struct ieee80211_hw *hw)
                wl->scanning = false;
        }
 
-       wl->state = WL12XX_STATE_OFF;
+       wl->state = WL1251_STATE_OFF;
 
-       wl12xx_disable_interrupts(wl);
+       wl1251_disable_interrupts(wl);
 
        mutex_unlock(&wl->mutex);
 
@@ -395,9 +408,8 @@ static void wl12xx_op_stop(struct ieee80211_hw *hw)
        mutex_lock(&wl->mutex);
 
        /* let's notify MAC80211 about the remaining pending TX frames */
-       wl12xx_tx_flush(wl);
-
-       wl12xx_power_off(wl);
+       wl->chip.op_tx_flush(wl);
+       wl1251_power_off(wl);
 
        memset(wl->bssid, 0, ETH_ALEN);
        wl->listen_int = 1;
@@ -412,21 +424,21 @@ static void wl12xx_op_stop(struct ieee80211_hw *hw)
        wl->elp = false;
        wl->psm = 0;
        wl->tx_queue_stopped = false;
-       wl->power_level = WL12XX_DEFAULT_POWER_LEVEL;
+       wl->power_level = WL1251_DEFAULT_POWER_LEVEL;
 
-       wl12xx_debugfs_reset(wl);
+       wl1251_debugfs_reset(wl);
 
        mutex_unlock(&wl->mutex);
 }
 
-static int wl12xx_op_add_interface(struct ieee80211_hw *hw,
+static int wl1251_op_add_interface(struct ieee80211_hw *hw,
                                   struct ieee80211_if_init_conf *conf)
 {
-       struct wl12xx *wl = hw->priv;
+       struct wl1251 *wl = hw->priv;
        DECLARE_MAC_BUF(mac);
        int ret = 0;
 
-       wl12xx_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %s",
+       wl1251_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %s",
                     conf->type, print_mac(mac, conf->mac_addr));
 
        mutex_lock(&wl->mutex);
@@ -446,7 +458,7 @@ static int wl12xx_op_add_interface(struct ieee80211_hw *hw,
        if (memcmp(wl->mac_addr, conf->mac_addr, ETH_ALEN)) {
                memcpy(wl->mac_addr, conf->mac_addr, ETH_ALEN);
                SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
-               ret = wl12xx_acx_station_id(wl);
+               ret = wl1251_acx_station_id(wl);
                if (ret < 0)
                        goto out;
        }
@@ -456,13 +468,13 @@ out:
        return ret;
 }
 
-static void wl12xx_op_remove_interface(struct ieee80211_hw *hw,
+static void wl1251_op_remove_interface(struct ieee80211_hw *hw,
                                         struct ieee80211_if_init_conf *conf)
 {
-       wl12xx_debug(DEBUG_MAC80211, "mac80211 remove interface");
+       wl1251_debug(DEBUG_MAC80211, "mac80211 remove interface");
 }
 
-static int wl12xx_build_null_data(struct wl12xx *wl)
+static int wl1251_build_null_data(struct wl1251 *wl)
 {
        struct wl12xx_null_data_template template;
 
@@ -478,12 +490,12 @@ static int wl12xx_build_null_data(struct wl12xx *wl)
        template.header.frame_ctl = cpu_to_le16(IEEE80211_FTYPE_DATA |
                                                IEEE80211_STYPE_NULLFUNC);
 
-       return wl12xx_cmd_template_set(wl, CMD_NULL_DATA, &template,
+       return wl1251_cmd_template_set(wl, CMD_NULL_DATA, &template,
                                       sizeof(template));
 
 }
 
-static int wl12xx_build_ps_poll(struct wl12xx *wl, u16 aid)
+static int wl1251_build_ps_poll(struct wl1251 *wl, u16 aid)
 {
        struct wl12xx_ps_poll_template template;
 
@@ -492,41 +504,45 @@ static int wl12xx_build_ps_poll(struct wl12xx *wl, u16 aid)
        template.aid = aid;
        template.fc = cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_PSPOLL);
 
-       return wl12xx_cmd_template_set(wl, CMD_PS_POLL, &template,
+       return wl1251_cmd_template_set(wl, CMD_PS_POLL, &template,
                                       sizeof(template));
 
 }
 
-static int wl12xx_op_config(struct ieee80211_hw *hw, u32 changed)
+static int wl1251_op_config(struct ieee80211_hw *hw, u32 changed)
 {
-       struct wl12xx *wl = hw->priv;
+       struct wl1251 *wl = hw->priv;
        struct ieee80211_conf *conf = &hw->conf;
        int channel, ret = 0;
 
        channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
 
-       wl12xx_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d",
+       wl1251_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d",
                     channel,
                     conf->flags & IEEE80211_CONF_PS ? "on" : "off",
                     conf->power_level);
 
        mutex_lock(&wl->mutex);
 
+       ret = wl1251_ps_elp_wakeup(wl);
+       if (ret < 0)
+               goto out;
+
        if (channel != wl->channel) {
                /* FIXME: use beacon interval provided by mac80211 */
-               ret = wl12xx_cmd_join(wl, wl->bss_type, 1, 100, 0);
+               ret = wl->chip.op_cmd_join(wl, wl->bss_type, 1, 100, 0);
                if (ret < 0)
-                       goto out;
+                       goto out_sleep;
 
                wl->channel = channel;
        }
 
-       ret = wl12xx_build_null_data(wl);
+       ret = wl1251_build_null_data(wl);
        if (ret < 0)
-               goto out;
+               goto out_sleep;
 
        if (conf->flags & IEEE80211_CONF_PS && !wl->psm_requested) {
-               wl12xx_info("psm enabled");
+               wl1251_debug(DEBUG_PSM, "psm enabled");
 
                wl->psm_requested = true;
 
@@ -535,49 +551,53 @@ static int wl12xx_op_config(struct ieee80211_hw *hw, u32 changed)
                 * If we're not, we'll enter it when joining an SSID,
                 * through the bss_info_changed() hook.
                 */
-               ret = wl12xx_ps_set_mode(wl, STATION_POWER_SAVE_MODE);
+               ret = wl1251_ps_set_mode(wl, STATION_POWER_SAVE_MODE);
        } else if (!(conf->flags & IEEE80211_CONF_PS) &&
                   wl->psm_requested) {
-               wl12xx_info("psm disabled");
+               wl1251_debug(DEBUG_PSM, "psm disabled");
 
                wl->psm_requested = false;
 
                if (wl->psm)
-                       ret = wl12xx_ps_set_mode(wl, STATION_ACTIVE_MODE);
+                       ret = wl1251_ps_set_mode(wl, STATION_ACTIVE_MODE);
        }
 
        if (conf->power_level != wl->power_level) {
-               ret = wl12xx_acx_tx_power(wl, conf->power_level);
+               ret = wl1251_acx_tx_power(wl, conf->power_level);
                if (ret < 0)
                        goto out;
 
                wl->power_level = conf->power_level;
        }
 
+out_sleep:
+       wl1251_ps_elp_sleep(wl);
+
 out:
        mutex_unlock(&wl->mutex);
+
        return ret;
 }
 
-#define WL12XX_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
+#define WL1251_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
                                  FIF_ALLMULTI | \
                                  FIF_FCSFAIL | \
                                  FIF_BCN_PRBRESP_PROMISC | \
                                  FIF_CONTROL | \
                                  FIF_OTHER_BSS)
 
-static void wl12xx_op_configure_filter(struct ieee80211_hw *hw,
+static void wl1251_op_configure_filter(struct ieee80211_hw *hw,
                                       unsigned int changed,
                                       unsigned int *total,
                                       int mc_count,
                                       struct dev_addr_list *mc_list)
 {
-       struct wl12xx *wl = hw->priv;
+       struct wl1251 *wl = hw->priv;
 
-       wl12xx_debug(DEBUG_MAC80211, "mac80211 configure filter");
+       wl1251_debug(DEBUG_MAC80211, "mac80211 configure filter");
 
-       *total &= WL12XX_SUPPORTED_FILTERS;
-       changed &= WL12XX_SUPPORTED_FILTERS;
+       *total &= WL1251_SUPPORTED_FILTERS;
+       changed &= WL1251_SUPPORTED_FILTERS;
 
        if (changed == 0)
                /* no filters which we support changed */
@@ -585,8 +605,8 @@ static void wl12xx_op_configure_filter(struct ieee80211_hw *hw,
 
        /* FIXME: wl->rx_config and wl->rx_filter are not protected */
 
-       wl->rx_config = WL12XX_DEFAULT_RX_CONFIG;
-       wl->rx_filter = WL12XX_DEFAULT_RX_FILTER;
+       wl->rx_config = WL1251_DEFAULT_RX_CONFIG;
+       wl->rx_filter = WL1251_DEFAULT_RX_FILTER;
 
        if (*total & FIF_PROMISC_IN_BSS) {
                wl->rx_config |= CFG_BSSID_FILTER_EN;
@@ -618,7 +638,8 @@ static void wl12xx_op_configure_filter(struct ieee80211_hw *hw,
 }
 
 /* HW encryption */
-static int wl12xx_set_key_type(struct wl12xx *wl, struct acx_set_key *key,
+static int wl1251_set_key_type(struct wl1251 *wl,
+                              struct wl1251_cmd_set_keys *key,
                               enum set_key_cmd cmd,
                               struct ieee80211_key_conf *mac80211_key,
                               const u8 *addr)
@@ -648,95 +669,116 @@ static int wl12xx_set_key_type(struct wl12xx *wl, struct acx_set_key *key,
                mac80211_key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
                break;
        default:
-               wl12xx_error("Unknown key algo 0x%x", mac80211_key->alg);
+               wl1251_error("Unknown key algo 0x%x", mac80211_key->alg);
                return -EOPNOTSUPP;
        }
 
        return 0;
 }
 
-static int wl12xx_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
+static int wl1251_op_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 wl12xx *wl = hw->priv;
-       struct acx_set_key wl_key;
+       struct wl1251 *wl = hw->priv;
+       struct wl1251_cmd_set_keys *wl_cmd;
        const u8 *addr;
        int ret;
 
        static const u8 bcast_addr[ETH_ALEN] =
                { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
 
-       wl12xx_debug(DEBUG_MAC80211, "mac80211 set key");
+       wl1251_debug(DEBUG_MAC80211, "mac80211 set key");
 
-       memset(&wl_key, 0, sizeof(wl_key));
+       wl_cmd = kzalloc(sizeof(*wl_cmd), GFP_KERNEL);
+       if (!wl_cmd) {
+               ret = -ENOMEM;
+               goto out;
+       }
 
        addr = sta ? sta->addr : bcast_addr;
 
-       wl12xx_debug(DEBUG_CRYPT, "CMD: 0x%x", cmd);
-       wl12xx_dump(DEBUG_CRYPT, "ADDR: ", addr, ETH_ALEN);
-       wl12xx_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
+       wl1251_debug(DEBUG_CRYPT, "CMD: 0x%x", cmd);
+       wl1251_dump(DEBUG_CRYPT, "ADDR: ", addr, ETH_ALEN);
+       wl1251_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
                     key->alg, key->keyidx, key->keylen, key->flags);
-       wl12xx_dump(DEBUG_CRYPT, "KEY: ", key->key, key->keylen);
+       wl1251_dump(DEBUG_CRYPT, "KEY: ", key->key, key->keylen);
+
+       if (is_zero_ether_addr(addr)) {
+               /* We dont support TX only encryption */
+               ret = -EOPNOTSUPP;
+               goto out;
+       }
 
        mutex_lock(&wl->mutex);
 
+       ret = wl1251_ps_elp_wakeup(wl);
+       if (ret < 0)
+               goto out_unlock;
+
        switch (cmd) {
        case SET_KEY:
-               wl_key.key_action = KEY_ADD_OR_REPLACE;
+               wl_cmd->key_action = KEY_ADD_OR_REPLACE;
                break;
        case DISABLE_KEY:
-               wl_key.key_action = KEY_REMOVE;
+               wl_cmd->key_action = KEY_REMOVE;
                break;
        default:
-               wl12xx_error("Unsupported key cmd 0x%x", cmd);
+               wl1251_error("Unsupported key cmd 0x%x", cmd);
                break;
        }
 
-       ret = wl12xx_set_key_type(wl, &wl_key, cmd, key, addr);
+       ret = wl1251_set_key_type(wl, wl_cmd, cmd, key, addr);
        if (ret < 0) {
-               wl12xx_error("Set KEY type failed");
-               goto out;
+               wl1251_error("Set KEY type failed");
+               goto out_sleep;
        }
 
-       if (wl_key.key_type != KEY_WEP_DEFAULT)
-               memcpy(wl_key.addr, addr, ETH_ALEN);
+       if (wl_cmd->key_type != KEY_WEP_DEFAULT)
+               memcpy(wl_cmd->addr, addr, ETH_ALEN);
 
-       if ((wl_key.key_type == KEY_TKIP_MIC_GROUP) ||
-           (wl_key.key_type == KEY_TKIP_MIC_PAIRWISE)) {
+       if ((wl_cmd->key_type == KEY_TKIP_MIC_GROUP) ||
+           (wl_cmd->key_type == KEY_TKIP_MIC_PAIRWISE)) {
                /*
                 * We get the key in the following form:
                 * TKIP (16 bytes) - TX MIC (8 bytes) - RX MIC (8 bytes)
                 * but the target is expecting:
                 * TKIP - RX MIC - TX MIC
                 */
-               memcpy(wl_key.key, key->key, 16);
-               memcpy(wl_key.key + 16, key->key + 24, 8);
-               memcpy(wl_key.key + 24, key->key + 16, 8);
+               memcpy(wl_cmd->key, key->key, 16);
+               memcpy(wl_cmd->key + 16, key->key + 24, 8);
+               memcpy(wl_cmd->key + 24, key->key + 16, 8);
 
        } else {
-               memcpy(wl_key.key, key->key, key->keylen);
+               memcpy(wl_cmd->key, key->key, key->keylen);
        }
-       wl_key.key_size = key->keylen;
+       wl_cmd->key_size = key->keylen;
 
-       wl_key.id = key->keyidx;
-       wl_key.ssid_profile = 0;
+       wl_cmd->id = key->keyidx;
+       wl_cmd->ssid_profile = 0;
 
-       wl12xx_dump(DEBUG_CRYPT, "TARGET KEY: ", &wl_key, sizeof(wl_key));
+       wl1251_dump(DEBUG_CRYPT, "TARGET KEY: ", wl_cmd, sizeof(*wl_cmd));
 
-       if (wl12xx_cmd_send(wl, CMD_SET_KEYS, &wl_key, sizeof(wl_key)) < 0) {
-               wl12xx_error("Set KEY failed");
-               ret = -EOPNOTSUPP;
-               goto out;
+       ret = wl1251_cmd_send(wl, CMD_SET_KEYS, wl_cmd, sizeof(*wl_cmd));
+       if (ret < 0) {
+               wl1251_warning("could not set keys");
+               goto out_sleep;
        }
 
-out:
+out_sleep:
+       wl1251_ps_elp_sleep(wl);
+
+out_unlock:
        mutex_unlock(&wl->mutex);
+
+out:
+       kfree(wl_cmd);
+
        return ret;
 }
 
-static int wl12xx_build_basic_rates(char *rates)
+static int wl1251_build_basic_rates(char *rates)
 {
        u8 index = 0;
 
@@ -748,7 +790,7 @@ static int wl12xx_build_basic_rates(char *rates)
        return index;
 }
 
-static int wl12xx_build_extended_rates(char *rates)
+static int wl1251_build_extended_rates(char *rates)
 {
        u8 index = 0;
 
@@ -765,7 +807,7 @@ static int wl12xx_build_extended_rates(char *rates)
 }
 
 
-static int wl12xx_build_probe_req(struct wl12xx *wl, u8 *ssid, size_t ssid_len)
+static int wl1251_build_probe_req(struct wl1251 *wl, u8 *ssid, size_t ssid_len)
 {
        struct wl12xx_probe_req_template template;
        struct wl12xx_ie_rates *rates;
@@ -792,31 +834,30 @@ static int wl12xx_build_probe_req(struct wl12xx *wl, u8 *ssid, size_t ssid_len)
        /* Basic Rates */
        rates = (struct wl12xx_ie_rates *)ptr;
        rates->header.id = WLAN_EID_SUPP_RATES;
-       rates->header.len = wl12xx_build_basic_rates(rates->rates);
+       rates->header.len = wl1251_build_basic_rates(rates->rates);
        size += sizeof(struct wl12xx_ie_header) + rates->header.len;
        ptr += sizeof(struct wl12xx_ie_header) + rates->header.len;
 
        /* Extended rates */
        rates = (struct wl12xx_ie_rates *)ptr;
        rates->header.id = WLAN_EID_EXT_SUPP_RATES;
-       rates->header.len = wl12xx_build_extended_rates(rates->rates);
+       rates->header.len = wl1251_build_extended_rates(rates->rates);
        size += sizeof(struct wl12xx_ie_header) + rates->header.len;
 
-       wl12xx_dump(DEBUG_SCAN, "PROBE REQ: ", &template, size);
+       wl1251_dump(DEBUG_SCAN, "PROBE REQ: ", &template, size);
 
-       return wl12xx_cmd_template_set(wl, CMD_PROBE_REQ, &template,
+       return wl1251_cmd_template_set(wl, CMD_PROBE_REQ, &template,
                                      size);
 }
 
-static int wl12xx_hw_scan(struct wl12xx *wl, u8 *ssid, size_t len,
+static int wl1251_hw_scan(struct wl1251 *wl, u8 *ssid, size_t len,
                          u8 active_scan, u8 high_prio, u8 num_channels,
                          u8 probe_requests)
 {
+       struct wl1251_cmd_trigger_scan_to *trigger = NULL;
+       struct cmd_scan *params = NULL;
        int i, ret;
-       u32 split_scan = 0;
        u16 scan_options = 0;
-       struct cmd_scan *params;
-       struct wl12xx_command *cmd_answer;
 
        if (wl->scanning)
                return -EINVAL;
@@ -864,33 +905,38 @@ static int wl12xx_hw_scan(struct wl12xx *wl, u8 *ssid, size_t len,
                memset(params->params.ssid, 0, 32);
        }
 
-       ret = wl12xx_build_probe_req(wl, ssid, len);
+       ret = wl1251_build_probe_req(wl, ssid, len);
        if (ret < 0) {
-               wl12xx_error("PROBE request template failed");
+               wl1251_error("PROBE request template failed");
                goto out;
        }
 
-       ret = wl12xx_cmd_send(wl, CMD_TRIGGER_SCAN_TO, &split_scan,
-                             sizeof(u32));
+       trigger = kzalloc(sizeof(*trigger), GFP_KERNEL);
+       if (!trigger)
+               goto out;
+
+       trigger->timeout = 0;
+
+       ret = wl1251_cmd_send(wl, CMD_TRIGGER_SCAN_TO, trigger,
+                             sizeof(*trigger));
        if (ret < 0) {
-               wl12xx_error("Split SCAN failed");
+               wl1251_error("trigger scan to failed for hw scan");
                goto out;
        }
 
-       wl12xx_dump(DEBUG_SCAN, "SCAN: ", params, sizeof(*params));
+       wl1251_dump(DEBUG_SCAN, "SCAN: ", params, sizeof(*params));
 
        wl->scanning = true;
 
-       ret = wl12xx_cmd_send(wl, CMD_SCAN, params, sizeof(*params));
+       ret = wl1251_cmd_send(wl, CMD_SCAN, params, sizeof(*params));
        if (ret < 0)
-               wl12xx_error("SCAN failed");
+               wl1251_error("SCAN failed");
 
-       wl12xx_spi_mem_read(wl, wl->cmd_box_addr, params, sizeof(*params));
+       wl1251_spi_mem_read(wl, wl->cmd_box_addr, params, sizeof(*params));
 
-       cmd_answer = (struct wl12xx_command *) params;
-       if (cmd_answer->status != CMD_STATUS_SUCCESS) {
-               wl12xx_error("TEST command answer error: %d",
-                            cmd_answer->status);
+       if (params->header.status != CMD_STATUS_SUCCESS) {
+               wl1251_error("TEST command answer error: %d",
+                            params->header.status);
                wl->scanning = false;
                ret = -EIO;
                goto out;
@@ -902,15 +948,15 @@ out:
 
 }
 
-static int wl12xx_op_hw_scan(struct ieee80211_hw *hw,
+static int wl1251_op_hw_scan(struct ieee80211_hw *hw,
                             struct cfg80211_scan_request *req)
 {
-       struct wl12xx *wl = hw->priv;
+       struct wl1251 *wl = hw->priv;
        int ret;
        u8 *ssid = NULL;
        size_t ssid_len = 0;
 
-       wl12xx_debug(DEBUG_MAC80211, "mac80211 hw scan");
+       wl1251_debug(DEBUG_MAC80211, "mac80211 hw scan");
 
        if (req->n_ssids) {
                ssid = req->ssids[0].ssid;
@@ -918,85 +964,108 @@ static int wl12xx_op_hw_scan(struct ieee80211_hw *hw,
        }
 
        mutex_lock(&wl->mutex);
-       ret = wl12xx_hw_scan(hw->priv, ssid, ssid_len, 1, 0, 13, 3);
+
+       ret = wl1251_ps_elp_wakeup(wl);
+       if (ret < 0)
+               goto out;
+
+       ret = wl1251_hw_scan(hw->priv, ssid, ssid_len, 1, 0, 13, 3);
+
+       wl1251_ps_elp_sleep(wl);
+
+out:
        mutex_unlock(&wl->mutex);
 
        return ret;
 }
 
-static int wl12xx_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
+static int wl1251_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
 {
-       struct wl12xx *wl = hw->priv;
+       struct wl1251 *wl = hw->priv;
        int ret;
 
-       ret = wl12xx_acx_rts_threshold(wl, (u16) value);
+       mutex_lock(&wl->mutex);
+
+       ret = wl1251_ps_elp_wakeup(wl);
+       if (ret < 0)
+               goto out;
 
+       ret = wl1251_acx_rts_threshold(wl, (u16) value);
        if (ret < 0)
-               wl12xx_warning("wl12xx_op_set_rts_threshold failed: %d", ret);
+               wl1251_warning("wl1251_op_set_rts_threshold failed: %d", ret);
+
+       wl1251_ps_elp_sleep(wl);
+
+out:
+       mutex_unlock(&wl->mutex);
 
        return ret;
 }
 
-static void wl12xx_op_bss_info_changed(struct ieee80211_hw *hw,
+static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw,
                                       struct ieee80211_vif *vif,
                                       struct ieee80211_bss_conf *bss_conf,
                                       u32 changed)
 {
-       enum acx_ps_mode mode;
-       struct wl12xx *wl = hw->priv;
+       enum wl1251_cmd_ps_mode mode;
+       struct wl1251 *wl = hw->priv;
        struct sk_buff *beacon;
        int ret;
 
-       wl12xx_debug(DEBUG_MAC80211, "mac80211 bss info changed");
+       wl1251_debug(DEBUG_MAC80211, "mac80211 bss info changed");
 
        mutex_lock(&wl->mutex);
 
+       ret = wl1251_ps_elp_wakeup(wl);
+       if (ret < 0)
+               goto out;
+
        if (changed & BSS_CHANGED_ASSOC) {
                if (bss_conf->assoc) {
                        wl->aid = bss_conf->aid;
 
-                       ret = wl12xx_build_ps_poll(wl, wl->aid);
+                       ret = wl1251_build_ps_poll(wl, wl->aid);
                        if (ret < 0)
-                               goto out;
+                               goto out_sleep;
 
-                       ret = wl12xx_acx_aid(wl, wl->aid);
+                       ret = wl1251_acx_aid(wl, wl->aid);
                        if (ret < 0)
-                               goto out;
+                               goto out_sleep;
 
                        /* If we want to go in PSM but we're not there yet */
                        if (wl->psm_requested && !wl->psm) {
                                mode = STATION_POWER_SAVE_MODE;
-                               ret = wl12xx_ps_set_mode(wl, mode);
+                               ret = wl1251_ps_set_mode(wl, mode);
                                if (ret < 0)
-                                       goto out;
+                                       goto out_sleep;
                        }
                }
        }
        if (changed & BSS_CHANGED_ERP_SLOT) {
                if (bss_conf->use_short_slot)
-                       ret = wl12xx_acx_slot(wl, SLOT_TIME_SHORT);
+                       ret = wl1251_acx_slot(wl, SLOT_TIME_SHORT);
                else
-                       ret = wl12xx_acx_slot(wl, SLOT_TIME_LONG);
+                       ret = wl1251_acx_slot(wl, SLOT_TIME_LONG);
                if (ret < 0) {
-                       wl12xx_warning("Set slot time failed %d", ret);
-                       goto out;
+                       wl1251_warning("Set slot time failed %d", ret);
+                       goto out_sleep;
                }
        }
 
        if (changed & BSS_CHANGED_ERP_PREAMBLE) {
                if (bss_conf->use_short_preamble)
-                       wl12xx_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
+                       wl1251_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
                else
-                       wl12xx_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
+                       wl1251_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
        }
 
        if (changed & BSS_CHANGED_ERP_CTS_PROT) {
                if (bss_conf->use_cts_prot)
-                       ret = wl12xx_acx_cts_protect(wl, CTSPROTECT_ENABLE);
+                       ret = wl1251_acx_cts_protect(wl, CTSPROTECT_ENABLE);
                else
-                       ret = wl12xx_acx_cts_protect(wl, CTSPROTECT_DISABLE);
+                       ret = wl1251_acx_cts_protect(wl, CTSPROTECT_DISABLE);
                if (ret < 0) {
-                       wl12xx_warning("Set ctsprotect failed %d", ret);
+                       wl1251_warning("Set ctsprotect failed %d", ret);
                        goto out;
                }
        }
@@ -1004,20 +1073,22 @@ static void wl12xx_op_bss_info_changed(struct ieee80211_hw *hw,
        if (changed & BSS_CHANGED_BSSID) {
                memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
 
-               ret = wl12xx_build_null_data(wl);
+               ret = wl1251_build_null_data(wl);
                if (ret < 0)
                        goto out;
 
                if (wl->bss_type != BSS_TYPE_IBSS) {
-                       ret = wl12xx_cmd_join(wl, wl->bss_type, 5, 100, 1);
+                       ret = wl1251_cmd_join(wl, wl->bss_type, 5, 100, 1);
                        if (ret < 0)
-                               goto out;
+                               goto out_sleep;
+                       wl1251_warning("Set ctsprotect failed %d", ret);
+                       goto out_sleep;
                }
        }
 
        if (changed & BSS_CHANGED_BEACON) {
                beacon = ieee80211_beacon_get(hw, vif);
-               ret = wl12xx_cmd_template_set(wl, CMD_BEACON, beacon->data,
+               ret = wl1251_cmd_template_set(wl, CMD_BEACON, beacon->data,
                                              beacon->len);
 
                if (ret < 0) {
@@ -1025,7 +1096,7 @@ static void wl12xx_op_bss_info_changed(struct ieee80211_hw *hw,
                        goto out;
                }
 
-               ret = wl12xx_cmd_template_set(wl, CMD_PROBE_RESP, beacon->data,
+               ret = wl1251_cmd_template_set(wl, CMD_PROBE_RESP, beacon->data,
                                              beacon->len);
 
                dev_kfree_skb(beacon);
@@ -1033,19 +1104,22 @@ static void wl12xx_op_bss_info_changed(struct ieee80211_hw *hw,
                if (ret < 0)
                        goto out;
 
-               ret = wl12xx_cmd_join(wl, wl->bss_type, 1, 100, 0);
+               ret = wl->chip.op_cmd_join(wl, wl->bss_type, 1, 100, 0);
 
                if (ret < 0)
                        goto out;
        }
 
+out_sleep:
+       wl1251_ps_elp_sleep(wl);
+
 out:
        mutex_unlock(&wl->mutex);
 }
 
 
 /* can't be const, mac80211 writes to this */
-static struct ieee80211_rate wl12xx_rates[] = {
+static struct ieee80211_rate wl1251_rates[] = {
        { .bitrate = 10,
          .hw_value = 0x1,
          .hw_value_short = 0x1, },
@@ -1088,7 +1162,7 @@ static struct ieee80211_rate wl12xx_rates[] = {
 };
 
 /* can't be const, mac80211 writes to this */
-static struct ieee80211_channel wl12xx_channels[] = {
+static struct ieee80211_channel wl1251_channels[] = {
        { .hw_value = 1, .center_freq = 2412},
        { .hw_value = 2, .center_freq = 2417},
        { .hw_value = 3, .center_freq = 2422},
@@ -1105,28 +1179,28 @@ static struct ieee80211_channel wl12xx_channels[] = {
 };
 
 /* can't be const, mac80211 writes to this */
-static struct ieee80211_supported_band wl12xx_band_2ghz = {
-       .channels = wl12xx_channels,
-       .n_channels = ARRAY_SIZE(wl12xx_channels),
-       .bitrates = wl12xx_rates,
-       .n_bitrates = ARRAY_SIZE(wl12xx_rates),
+static struct ieee80211_supported_band wl1251_band_2ghz = {
+       .channels = wl1251_channels,
+       .n_channels = ARRAY_SIZE(wl1251_channels),
+       .bitrates = wl1251_rates,
+       .n_bitrates = ARRAY_SIZE(wl1251_rates),
 };
 
-static const struct ieee80211_ops wl12xx_ops = {
-       .start = wl12xx_op_start,
-       .stop = wl12xx_op_stop,
-       .add_interface = wl12xx_op_add_interface,
-       .remove_interface = wl12xx_op_remove_interface,
-       .config = wl12xx_op_config,
-       .configure_filter = wl12xx_op_configure_filter,
-       .tx = wl12xx_op_tx,
-       .set_key = wl12xx_op_set_key,
-       .hw_scan = wl12xx_op_hw_scan,
-       .bss_info_changed = wl12xx_op_bss_info_changed,
-       .set_rts_threshold = wl12xx_op_set_rts_threshold,
+static const struct ieee80211_ops wl1251_ops = {
+       .start = wl1251_op_start,
+       .stop = wl1251_op_stop,
+       .add_interface = wl1251_op_add_interface,
+       .remove_interface = wl1251_op_remove_interface,
+       .config = wl1251_op_config,
+       .configure_filter = wl1251_op_configure_filter,
+       .tx = wl1251_op_tx,
+       .set_key = wl1251_op_set_key,
+       .hw_scan = wl1251_op_hw_scan,
+       .bss_info_changed = wl1251_op_bss_info_changed,
+       .set_rts_threshold = wl1251_op_set_rts_threshold,
 };
 
-static int wl12xx_register_hw(struct wl12xx *wl)
+static int wl1251_register_hw(struct wl1251 *wl)
 {
        int ret;
 
@@ -1137,22 +1211,22 @@ static int wl12xx_register_hw(struct wl12xx *wl)
 
        ret = ieee80211_register_hw(wl->hw);
        if (ret < 0) {
-               wl12xx_error("unable to register mac80211 hw: %d", ret);
+               wl1251_error("unable to register mac80211 hw: %d", ret);
                return ret;
        }
 
        wl->mac80211_registered = true;
 
-       wl12xx_notice("loaded");
+       wl1251_notice("loaded");
 
        return 0;
 }
 
-static int wl12xx_init_ieee80211(struct wl12xx *wl)
+static int wl1251_init_ieee80211(struct wl1251 *wl)
 {
        /* The tx descriptor buffer and the TKIP space */
        wl->hw->extra_tx_headroom = sizeof(struct tx_double_buffer_desc)
-               + WL12XX_TKIP_IV_SPACE;
+               + WL1251_TKIP_IV_SPACE;
 
        /* unit us */
        /* FIXME: find a proper value */
@@ -1163,31 +1237,31 @@ static int wl12xx_init_ieee80211(struct wl12xx *wl)
 
        wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
        wl->hw->wiphy->max_scan_ssids = 1;
-       wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl12xx_band_2ghz;
+       wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1251_band_2ghz;
 
        SET_IEEE80211_DEV(wl->hw, &wl->spi->dev);
 
        return 0;
 }
 
-#define WL12XX_DEFAULT_CHANNEL 1
-static int __devinit wl12xx_probe(struct spi_device *spi)
+#define WL1251_DEFAULT_CHANNEL 1
+static int __devinit wl1251_probe(struct spi_device *spi)
 {
        struct wl12xx_platform_data *pdata;
        struct ieee80211_hw *hw;
-       struct wl12xx *wl;
+       struct wl1251 *wl;
        int ret, i;
        static const u8 nokia_oui[3] = {0x00, 0x1f, 0xdf};
 
        pdata = spi->dev.platform_data;
        if (!pdata) {
-               wl12xx_error("no platform data");
+               wl1251_error("no platform data");
                return -ENODEV;
        }
 
-       hw = ieee80211_alloc_hw(sizeof(*wl), &wl12xx_ops);
+       hw = ieee80211_alloc_hw(sizeof(*wl), &wl1251_ops);
        if (!hw) {
-               wl12xx_error("could not alloc ieee80211_hw");
+               wl1251_error("could not alloc ieee80211_hw");
                return -ENOMEM;
        }
 
@@ -1202,9 +1276,8 @@ static int __devinit wl12xx_probe(struct spi_device *spi)
 
        skb_queue_head_init(&wl->tx_queue);
 
-       INIT_WORK(&wl->tx_work, wl12xx_tx_work);
-       INIT_WORK(&wl->filter_work, wl12xx_filter_work);
-       wl->channel = WL12XX_DEFAULT_CHANNEL;
+       INIT_WORK(&wl->filter_work, wl1251_filter_work);
+       wl->channel = WL1251_DEFAULT_CHANNEL;
        wl->scanning = false;
        wl->default_key = 0;
        wl->listen_int = 1;
@@ -1212,17 +1285,17 @@ static int __devinit wl12xx_probe(struct spi_device *spi)
        wl->rx_handled = 0;
        wl->rx_current_buffer = 0;
        wl->rx_last_id = 0;
-       wl->rx_config = WL12XX_DEFAULT_RX_CONFIG;
-       wl->rx_filter = WL12XX_DEFAULT_RX_FILTER;
+       wl->rx_config = WL1251_DEFAULT_RX_CONFIG;
+       wl->rx_filter = WL1251_DEFAULT_RX_FILTER;
        wl->elp = false;
        wl->psm = 0;
        wl->psm_requested = false;
        wl->tx_queue_stopped = false;
-       wl->power_level = WL12XX_DEFAULT_POWER_LEVEL;
+       wl->power_level = WL1251_DEFAULT_POWER_LEVEL;
 
        /* We use the default power on sleep time until we know which chip
         * we're using */
-       wl->chip.power_on_sleep = WL12XX_DEFAULT_POWER_ON_SLEEP;
+       wl->chip.power_on_sleep = WL1251_DEFAULT_POWER_ON_SLEEP;
 
        for (i = 0; i < FW_TX_CMPLT_BLOCK_SIZE; i++)
                wl->tx_frames[i] = NULL;
@@ -1236,37 +1309,46 @@ static int __devinit wl12xx_probe(struct spi_device *spi)
        memcpy(wl->mac_addr, nokia_oui, 3);
        get_random_bytes(wl->mac_addr + 3, 3);
 
-       wl->state = WL12XX_STATE_OFF;
+       wl->state = WL1251_STATE_OFF;
        mutex_init(&wl->mutex);
 
        wl->tx_mgmt_frm_rate = DEFAULT_HW_GEN_TX_RATE;
        wl->tx_mgmt_frm_mod = DEFAULT_HW_GEN_MODULATION_TYPE;
 
+       wl->rx_descriptor = kmalloc(sizeof(*wl->rx_descriptor), GFP_KERNEL);
+       if (!wl->rx_descriptor) {
+               wl1251_error("could not allocate memory for rx descriptor");
+               ret = -ENOMEM;
+               goto out_free;
+       }
+
        /* This is the only SPI value that we need to set here, the rest
         * comes from the board-peripherals file */
        spi->bits_per_word = 32;
 
        ret = spi_setup(spi);
        if (ret < 0) {
-               wl12xx_error("spi_setup failed");
+               wl1251_error("spi_setup failed");
                goto out_free;
        }
 
        wl->set_power = pdata->set_power;
        if (!wl->set_power) {
-               wl12xx_error("set power function missing in platform data");
-               return -ENODEV;
+               wl1251_error("set power function missing in platform data");
+               ret = -ENODEV;
+               goto out_free;
        }
 
        wl->irq = spi->irq;
        if (wl->irq < 0) {
-               wl12xx_error("irq missing in platform data");
-               return -ENODEV;
+               wl1251_error("irq missing in platform data");
+               ret = -ENODEV;
+               goto out_free;
        }
 
-       ret = request_irq(wl->irq, wl12xx_irq, 0, DRIVER_NAME, wl);
+       ret = request_irq(wl->irq, wl1251_irq, 0, DRIVER_NAME, wl);
        if (ret < 0) {
-               wl12xx_error("request_irq() failed: %d", ret);
+               wl1251_error("request_irq() failed: %d", ret);
                goto out_free;
        }
 
@@ -1274,17 +1356,17 @@ static int __devinit wl12xx_probe(struct spi_device *spi)
 
        disable_irq(wl->irq);
 
-       ret = wl12xx_init_ieee80211(wl);
+       ret = wl1251_init_ieee80211(wl);
        if (ret)
                goto out_irq;
 
-       ret = wl12xx_register_hw(wl);
+       ret = wl1251_register_hw(wl);
        if (ret)
                goto out_irq;
 
-       wl12xx_debugfs_init(wl);
+       wl1251_debugfs_init(wl);
 
-       wl12xx_notice("initialized");
+       wl1251_notice("initialized");
 
        return 0;
 
@@ -1292,18 +1374,21 @@ static int __devinit wl12xx_probe(struct spi_device *spi)
        free_irq(wl->irq, wl);
 
  out_free:
+       kfree(wl->rx_descriptor);
+       wl->rx_descriptor = NULL;
+
        ieee80211_free_hw(hw);
 
        return ret;
 }
 
-static int __devexit wl12xx_remove(struct spi_device *spi)
+static int __devexit wl1251_remove(struct spi_device *spi)
 {
-       struct wl12xx *wl = dev_get_drvdata(&spi->dev);
+       struct wl1251 *wl = dev_get_drvdata(&spi->dev);
 
        ieee80211_unregister_hw(wl->hw);
 
-       wl12xx_debugfs_exit(wl);
+       wl1251_debugfs_exit(wl);
 
        free_irq(wl->irq, wl);
        kfree(wl->target_mem_map);
@@ -1312,30 +1397,35 @@ static int __devexit wl12xx_remove(struct spi_device *spi)
        wl->fw = NULL;
        kfree(wl->nvs);
        wl->nvs = NULL;
+
+       kfree(wl->rx_descriptor);
+       wl->rx_descriptor = NULL;
+
        ieee80211_free_hw(wl->hw);
 
        return 0;
 }
 
 
-static struct spi_driver wl12xx_spi_driver = {
+static struct spi_driver wl1251_spi_driver = {
        .driver = {
+               /* FIXME: use wl12xx name to not break the user space */
                .name           = "wl12xx",
                .bus            = &spi_bus_type,
                .owner          = THIS_MODULE,
        },
 
-       .probe          = wl12xx_probe,
-       .remove         = __devexit_p(wl12xx_remove),
+       .probe          = wl1251_probe,
+       .remove         = __devexit_p(wl1251_remove),
 };
 
-static int __init wl12xx_init(void)
+static int __init wl1251_init(void)
 {
        int ret;
 
-       ret = spi_register_driver(&wl12xx_spi_driver);
+       ret = spi_register_driver(&wl1251_spi_driver);
        if (ret < 0) {
-               wl12xx_error("failed to register spi driver: %d", ret);
+               wl1251_error("failed to register spi driver: %d", ret);
                goto out;
        }
 
@@ -1343,15 +1433,15 @@ out:
        return ret;
 }
 
-static void __exit wl12xx_exit(void)
+static void __exit wl1251_exit(void)
 {
-       spi_unregister_driver(&wl12xx_spi_driver);
+       spi_unregister_driver(&wl1251_spi_driver);
 
-       wl12xx_notice("unloaded");
+       wl1251_notice("unloaded");
 }
 
-module_init(wl12xx_init);
-module_exit(wl12xx_exit);
+module_init(wl1251_init);
+module_exit(wl1251_exit);
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Kalle Valo <Kalle.Valo@nokia.com>, "
diff --git a/drivers/net/wireless/wl12xx/wl1251_netlink.c b/drivers/net/wireless/wl12xx/wl1251_netlink.c
new file mode 100644 (file)
index 0000000..67d3d5a
--- /dev/null
@@ -0,0 +1,679 @@
+/*
+ * This file is part of wl1251
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ *
+ * Contact: Kalle Valo <kalle.valo@nokia.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 St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+#include "wl1251_netlink.h"
+
+#include <linux/mutex.h>
+#include <linux/socket.h>
+#include <net/net_namespace.h>
+#include <net/sock.h>
+#include <net/genetlink.h>
+#include <net/wireless.h>
+#include <net/mac80211.h>
+
+#include "wl1251.h"
+#include "wl1251_spi.h"
+#include "wl1251_acx.h"
+
+/* FIXME: this should be changed as soon as user space catches up */
+#define WL1251_NL_NAME "wl1251"
+#define WL1251_NL_VERSION 1
+
+#define WL1251_MAX_TEST_LENGTH 1024
+#define WL1251_MAX_NVS_LENGTH 1024
+
+enum wl1251_nl_commands {
+       WL1251_NL_CMD_UNSPEC,
+       WL1251_NL_CMD_TEST,
+       WL1251_NL_CMD_INTERROGATE,
+       WL1251_NL_CMD_CONFIGURE,
+       WL1251_NL_CMD_PHY_REG_READ,
+       WL1251_NL_CMD_NVS_PUSH,
+       WL1251_NL_CMD_REG_WRITE,
+       WL1251_NL_CMD_REG_READ,
+       WL1251_NL_CMD_SET_PLT_MODE,
+
+       __WL1251_NL_CMD_AFTER_LAST
+};
+#define WL1251_NL_CMD_MAX (__WL1251_NL_CMD_AFTER_LAST - 1)
+
+enum wl1251_nl_attrs {
+       WL1251_NL_ATTR_UNSPEC,
+       WL1251_NL_ATTR_IFNAME,
+       WL1251_NL_ATTR_CMD_TEST_PARAM,
+       WL1251_NL_ATTR_CMD_TEST_ANSWER,
+       WL1251_NL_ATTR_CMD_IE,
+       WL1251_NL_ATTR_CMD_IE_LEN,
+       WL1251_NL_ATTR_CMD_IE_BUFFER,
+       WL1251_NL_ATTR_CMD_IE_ANSWER,
+       WL1251_NL_ATTR_REG_ADDR,
+       WL1251_NL_ATTR_REG_VAL,
+       WL1251_NL_ATTR_NVS_BUFFER,
+       WL1251_NL_ATTR_NVS_LEN,
+       WL1251_NL_ATTR_PLT_MODE,
+
+       __WL1251_NL_ATTR_AFTER_LAST
+};
+#define WL1251_NL_ATTR_MAX (__WL1251_NL_ATTR_AFTER_LAST - 1)
+
+static struct genl_family wl1251_nl_family = {
+       .id = GENL_ID_GENERATE,
+       .name = WL1251_NL_NAME,
+       .hdrsize = 0,
+       .version = WL1251_NL_VERSION,
+       .maxattr = WL1251_NL_ATTR_MAX,
+};
+
+static struct net_device *ifname_to_netdev(struct net *net,
+                                          struct genl_info *info)
+{
+       char *ifname;
+
+       if (!info->attrs[WL1251_NL_ATTR_IFNAME])
+               return NULL;
+
+       ifname = nla_data(info->attrs[WL1251_NL_ATTR_IFNAME]);
+
+       wl1251_debug(DEBUG_NETLINK, "Looking for %s", ifname);
+
+       return dev_get_by_name(net, ifname);
+}
+
+static struct wl1251 *ifname_to_wl1251(struct net *net, struct genl_info *info)
+{
+       struct net_device *netdev;
+       struct wireless_dev *wdev;
+       struct wiphy *wiphy;
+       struct ieee80211_hw *hw;
+
+       netdev = ifname_to_netdev(net, info);
+       if (netdev == NULL) {
+               wl1251_error("Wrong interface");
+               return NULL;
+       }
+
+       wdev = netdev->ieee80211_ptr;
+       if (wdev == NULL) {
+               wl1251_error("ieee80211_ptr is NULL");
+               return NULL;
+       }
+
+       wiphy = wdev->wiphy;
+       if (wiphy == NULL) {
+               wl1251_error("wiphy is NULL");
+               return NULL;
+       }
+
+       hw = wiphy_priv(wiphy);
+       if (hw == NULL) {
+               wl1251_error("hw is NULL");
+               return NULL;
+       }
+
+       dev_put(netdev);
+
+       return hw->priv;
+}
+
+static int wl1251_nl_test_cmd(struct sk_buff *skb, struct genl_info *info)
+{
+       struct wl1251 *wl;
+       struct wl1251_command *cmd;
+       char *buf;
+       int buf_len, ret, cmd_len;
+       u8 answer;
+
+       if (!info->attrs[WL1251_NL_ATTR_CMD_TEST_PARAM])
+               return -EINVAL;
+
+       wl = ifname_to_wl1251(&init_net, info);
+       if (wl == NULL) {
+               wl1251_error("wl1251 not found");
+               return -EINVAL;
+       }
+
+       cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+       if (!cmd)
+               return -ENOMEM;
+
+       buf = nla_data(info->attrs[WL1251_NL_ATTR_CMD_TEST_PARAM]);
+       buf_len = nla_len(info->attrs[WL1251_NL_ATTR_CMD_TEST_PARAM]);
+       answer = nla_get_u8(info->attrs[WL1251_NL_ATTR_CMD_TEST_ANSWER]);
+
+       cmd->header.id = CMD_TEST;
+       memcpy(cmd->parameters, buf, buf_len);
+       cmd_len = sizeof(struct wl1251_cmd_header) + buf_len;
+
+       mutex_lock(&wl->mutex);
+       ret = wl1251_cmd_test(wl, cmd, cmd_len, answer);
+       mutex_unlock(&wl->mutex);
+
+       if (ret < 0) {
+               wl1251_error("%s() failed", __func__);
+               goto out;
+       }
+
+       if (answer) {
+               struct sk_buff *msg;
+               void *hdr;
+
+               msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
+               if (!msg) {
+                       ret = -ENOMEM;
+                       goto out;
+               }
+
+               hdr = genlmsg_put(msg, info->snd_pid, info->snd_seq,
+                                 &wl1251_nl_family, 0, WL1251_NL_CMD_TEST);
+               if (IS_ERR(hdr)) {
+                       ret = PTR_ERR(hdr);
+                       goto nla_put_failure;
+               }
+
+               NLA_PUT_STRING(msg, WL1251_NL_ATTR_IFNAME,
+                              nla_data(info->attrs[WL1251_NL_ATTR_IFNAME]));
+               NLA_PUT(msg, WL1251_NL_ATTR_CMD_TEST_ANSWER,
+                       sizeof(*cmd), cmd);
+
+               ret = genlmsg_end(msg, hdr);
+               if (ret < 0) {
+                       wl1251_error("%s() failed", __func__);
+                       goto nla_put_failure;
+               }
+
+               wl1251_debug(DEBUG_NETLINK, "TEST cmd sent, answer");
+               ret = genlmsg_reply(msg, info);
+               goto out;
+
+ nla_put_failure:
+               nlmsg_free(msg);
+       } else
+               wl1251_debug(DEBUG_NETLINK, "TEST cmd sent");
+
+out:
+       kfree(cmd);
+       return ret;
+}
+
+static int wl1251_nl_interrogate(struct sk_buff *skb, struct genl_info *info)
+{
+       struct wl1251 *wl;
+       struct sk_buff *msg;
+       int ret = -ENOBUFS, cmd_ie, cmd_ie_len;
+       struct wl1251_command *cmd;
+       void *hdr;
+
+       if (!info->attrs[WL1251_NL_ATTR_CMD_IE])
+               return -EINVAL;
+
+       if (!info->attrs[WL1251_NL_ATTR_CMD_IE_LEN])
+               return -EINVAL;
+
+       cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+       if (!cmd)
+               return -ENOMEM;
+
+       msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
+       if (!msg)
+               return -ENOMEM;
+
+       wl = ifname_to_wl1251(&init_net, info);
+       if (wl == NULL) {
+               wl1251_error("wl1251 not found");
+               ret = -EINVAL;
+               goto nla_put_failure;
+       }
+
+       /* acx id */
+       cmd_ie = nla_get_u32(info->attrs[WL1251_NL_ATTR_CMD_IE]);
+
+       /* maximum length of acx, including all headers */
+       cmd_ie_len = nla_get_u32(info->attrs[WL1251_NL_ATTR_CMD_IE_LEN]);
+
+       wl1251_debug(DEBUG_NETLINK, "Getting IE 0x%x (len %d)",
+                    cmd_ie, cmd_ie_len);
+
+       mutex_lock(&wl->mutex);
+       ret = wl1251_cmd_interrogate(wl, cmd_ie, cmd, cmd_ie_len);
+       mutex_unlock(&wl->mutex);
+
+       if (ret < 0) {
+               wl1251_error("%s() failed", __func__);
+               goto nla_put_failure;
+       }
+
+       hdr = genlmsg_put(msg, info->snd_pid, info->snd_seq,
+                         &wl1251_nl_family, 0, WL1251_NL_CMD_INTERROGATE);
+       if (IS_ERR(hdr)) {
+               ret = PTR_ERR(hdr);
+               goto nla_put_failure;
+       }
+
+       NLA_PUT_STRING(msg, WL1251_NL_ATTR_IFNAME,
+                      nla_data(info->attrs[WL1251_NL_ATTR_IFNAME]));
+       NLA_PUT(msg, WL1251_NL_ATTR_CMD_IE_ANSWER, cmd_ie_len, cmd);
+
+       ret = genlmsg_end(msg, hdr);
+       if (ret < 0) {
+               wl1251_error("%s() failed", __func__);
+               goto nla_put_failure;
+       }
+
+       kfree(cmd);
+       return genlmsg_reply(msg, info);
+
+ nla_put_failure:
+       kfree(cmd);
+       nlmsg_free(msg);
+
+       return ret;
+}
+
+static int wl1251_nl_configure(struct sk_buff *skb, struct genl_info *info)
+{
+       int ret = 0, cmd_ie_len, acx_len;
+       struct acx_header *acx = NULL;
+       struct sk_buff *msg;
+       struct wl1251 *wl;
+       void *cmd_ie;
+       u16 *id;
+
+       if (!info->attrs[WL1251_NL_ATTR_CMD_IE_BUFFER])
+               return -EINVAL;
+
+       if (!info->attrs[WL1251_NL_ATTR_CMD_IE_LEN])
+               return -EINVAL;
+
+       msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
+       if (!msg)
+               return -ENOMEM;
+
+       wl = ifname_to_wl1251(&init_net, info);
+       if (wl == NULL) {
+               wl1251_error("wl1251 not found");
+               ret = -EINVAL;
+               goto nla_put_failure;
+       }
+
+       /* contains the acx header but not the cmd header */
+       cmd_ie = nla_data(info->attrs[WL1251_NL_ATTR_CMD_IE_BUFFER]);
+
+       cmd_ie_len = nla_get_u32(info->attrs[WL1251_NL_ATTR_CMD_IE_LEN]);
+
+       /* acx id is in the first two bytes */
+       id = cmd_ie;
+
+       /* need to add acx_header before cmd_ie, so create a new command */
+       acx_len = sizeof(struct acx_header) + cmd_ie_len;
+       acx = kzalloc(acx_len, GFP_KERNEL);
+       if (!acx) {
+               ret = -ENOMEM;
+               goto nla_put_failure;
+       }
+
+       /* copy the acx header and the payload */
+       memcpy(&acx->id, cmd_ie, cmd_ie_len);
+
+       mutex_lock(&wl->mutex);
+       ret = wl1251_cmd_configure(wl, *id, acx, acx_len);
+       mutex_unlock(&wl->mutex);
+
+       if (ret < 0) {
+               wl1251_error("%s() failed", __func__);
+               goto nla_put_failure;
+       }
+
+       wl1251_debug(DEBUG_NETLINK, "CONFIGURE cmd sent");
+
+ nla_put_failure:
+       kfree(acx);
+       nlmsg_free(msg);
+
+       return ret;
+}
+
+static int wl1251_nl_phy_reg_read(struct sk_buff *skb, struct genl_info *info)
+{
+       struct wl1251 *wl;
+       struct sk_buff *msg;
+       u32 reg_addr, *reg_value = NULL;
+       int ret = 0;
+       void *hdr;
+
+       if (!info->attrs[WL1251_NL_ATTR_REG_ADDR])
+               return -EINVAL;
+
+       msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
+       if (!msg)
+               return -ENOMEM;
+
+       wl = ifname_to_wl1251(&init_net, info);
+       if (wl == NULL) {
+               wl1251_error("wl1251 not found");
+               ret = -EINVAL;
+               goto nla_put_failure;
+       }
+
+       reg_value = kmalloc(sizeof(*reg_value), GFP_KERNEL);
+       if (!reg_value) {
+               ret = -ENOMEM;
+               goto nla_put_failure;
+       }
+
+       reg_addr = nla_get_u32(info->attrs[WL1251_NL_ATTR_REG_ADDR]);
+
+       wl1251_debug(DEBUG_NETLINK, "Reading PHY reg 0x%x", reg_addr);
+
+       mutex_lock(&wl->mutex);
+       ret = wl1251_cmd_read_memory(wl, reg_addr, reg_value,
+                                    sizeof(*reg_value));
+       mutex_unlock(&wl->mutex);
+
+       if (ret < 0) {
+               wl1251_error("%s() failed", __func__);
+               goto nla_put_failure;
+       }
+
+
+       hdr = genlmsg_put(msg, info->snd_pid, info->snd_seq,
+                         &wl1251_nl_family, 0, WL1251_NL_CMD_PHY_REG_READ);
+       if (IS_ERR(hdr)) {
+               ret = PTR_ERR(hdr);
+               goto nla_put_failure;
+       }
+
+       NLA_PUT_STRING(msg, WL1251_NL_ATTR_IFNAME,
+                      nla_data(info->attrs[WL1251_NL_ATTR_IFNAME]));
+
+       NLA_PUT_U32(msg, WL1251_NL_ATTR_REG_VAL, *reg_value);
+
+       ret = genlmsg_end(msg, hdr);
+       if (ret < 0) {
+               wl1251_error("%s() failed", __func__);
+               goto nla_put_failure;
+       }
+
+       kfree(reg_value);
+
+       return genlmsg_reply(msg, info);
+
+ nla_put_failure:
+       nlmsg_free(msg);
+       kfree(reg_value);
+
+       return ret;
+}
+
+static int wl1251_nl_nvs_push(struct sk_buff *skb, struct genl_info *info)
+{
+       struct wl1251 *wl;
+       int ret = 0;
+
+       if (!info->attrs[WL1251_NL_ATTR_NVS_BUFFER])
+               return -EINVAL;
+
+       if (!info->attrs[WL1251_NL_ATTR_NVS_LEN])
+               return -EINVAL;
+
+       wl = ifname_to_wl1251(&init_net, info);
+       if (wl == NULL) {
+               wl1251_error("wl1251 not found");
+               return -EINVAL;
+       }
+
+       mutex_lock(&wl->mutex);
+       wl->nvs_len = nla_get_u32(info->attrs[WL1251_NL_ATTR_NVS_LEN]);
+       if (wl->nvs_len % 4) {
+               wl1251_error("NVS size is not multiple of 32: %d", wl->nvs_len);
+               ret = -EILSEQ;
+               goto out;
+       }
+
+       /* If we already have an NVS, we should free it */
+       kfree(wl->nvs);
+
+       wl->nvs = kzalloc(wl->nvs_len, GFP_KERNEL);
+       if (wl->nvs == NULL) {
+               wl1251_error("Can't allocate NVS");
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       memcpy(wl->nvs,
+              nla_data(info->attrs[WL1251_NL_ATTR_NVS_BUFFER]),
+              wl->nvs_len);
+
+       wl1251_debug(DEBUG_NETLINK, "got NVS from userspace, %d bytes",
+                    wl->nvs_len);
+
+out:
+       mutex_unlock(&wl->mutex);
+
+       return ret;
+}
+
+static int wl1251_nl_reg_read(struct sk_buff *skb, struct genl_info *info)
+{
+       struct wl1251 *wl;
+       u32 addr, val;
+       int ret = 0;
+       struct sk_buff *msg;
+       void *hdr;
+
+       if (!info->attrs[WL1251_NL_ATTR_REG_ADDR])
+               return -EINVAL;
+
+       msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
+       if (!msg)
+               return -ENOMEM;
+
+       wl = ifname_to_wl1251(&init_net, info);
+       if (wl == NULL) {
+               wl1251_error("wl1251 not found");
+               return -EINVAL;
+       }
+
+       addr = nla_get_u32(info->attrs[WL1251_NL_ATTR_REG_ADDR]);
+
+       mutex_lock(&wl->mutex);
+       val = wl1251_reg_read32(wl, addr);
+       mutex_unlock(&wl->mutex);
+
+       hdr = genlmsg_put(msg, info->snd_pid, info->snd_seq,
+                         &wl1251_nl_family, 0, WL1251_NL_CMD_PHY_REG_READ);
+       if (IS_ERR(hdr)) {
+               ret = PTR_ERR(hdr);
+               goto nla_put_failure;
+       }
+
+       NLA_PUT_STRING(msg, WL1251_NL_ATTR_IFNAME,
+                      nla_data(info->attrs[WL1251_NL_ATTR_IFNAME]));
+
+       NLA_PUT_U32(msg, WL1251_NL_ATTR_REG_VAL, val);
+
+       ret = genlmsg_end(msg, hdr);
+       if (ret < 0) {
+               wl1251_error("%s() failed", __func__);
+               goto nla_put_failure;
+       }
+
+       return genlmsg_reply(msg, info);
+
+ nla_put_failure:
+       nlmsg_free(msg);
+
+       return ret;
+}
+
+static int wl1251_nl_reg_write(struct sk_buff *skb, struct genl_info *info)
+{
+       struct wl1251 *wl;
+       u32 addr, val;
+
+       if (!info->attrs[WL1251_NL_ATTR_REG_ADDR])
+               return -EINVAL;
+
+       if (!info->attrs[WL1251_NL_ATTR_REG_VAL])
+               return -EINVAL;
+
+       wl = ifname_to_wl1251(&init_net, info);
+       if (wl == NULL) {
+               wl1251_error("wl1251 not found");
+               return -EINVAL;
+       }
+
+       addr = nla_get_u32(info->attrs[WL1251_NL_ATTR_REG_ADDR]);
+       val = nla_get_u32(info->attrs[WL1251_NL_ATTR_REG_VAL]);
+
+       mutex_lock(&wl->mutex);
+       wl1251_reg_write32(wl, addr, val);
+       mutex_unlock(&wl->mutex);
+
+       return 0;
+}
+
+static int wl1251_nl_set_plt_mode(struct sk_buff *skb, struct genl_info *info)
+{
+       struct wl1251 *wl;
+       u32 val;
+       int ret;
+
+       if (!info->attrs[WL1251_NL_ATTR_PLT_MODE])
+               return -EINVAL;
+
+       wl = ifname_to_wl1251(&init_net, info);
+       if (wl == NULL) {
+               wl1251_error("wl1251 not found");
+               return -EINVAL;
+       }
+
+       val = nla_get_u32(info->attrs[WL1251_NL_ATTR_PLT_MODE]);
+
+       switch (val) {
+       case 0:
+               ret = wl1251_plt_stop(wl);
+               break;
+       case 1:
+               ret = wl1251_plt_start(wl);
+               break;
+       default:
+               ret = -EINVAL;
+               break;
+       }
+
+       return ret;
+}
+
+static struct nla_policy wl1251_nl_policy[WL1251_NL_ATTR_MAX + 1] = {
+       [WL1251_NL_ATTR_IFNAME] =            { .type = NLA_NUL_STRING,
+                                              .len = IFNAMSIZ-1 },
+       [WL1251_NL_ATTR_CMD_TEST_PARAM] =    { .type = NLA_BINARY,
+                                              .len = WL1251_MAX_TEST_LENGTH },
+       [WL1251_NL_ATTR_CMD_TEST_ANSWER] =   { .type = NLA_U8 },
+       [WL1251_NL_ATTR_CMD_IE] =            { .type = NLA_U32 },
+       [WL1251_NL_ATTR_CMD_IE_LEN] =        { .type = NLA_U32 },
+       [WL1251_NL_ATTR_CMD_IE_BUFFER] =     { .type = NLA_BINARY,
+                                              .len = WL1251_MAX_TEST_LENGTH },
+       [WL1251_NL_ATTR_CMD_IE_ANSWER] =     { .type = NLA_BINARY,
+                                              .len = WL1251_MAX_TEST_LENGTH },
+       [WL1251_NL_ATTR_REG_ADDR] =          { .type = NLA_U32 },
+       [WL1251_NL_ATTR_REG_VAL] =           { .type = NLA_U32 },
+       [WL1251_NL_ATTR_NVS_BUFFER] =        { .type = NLA_BINARY,
+                                              .len = WL1251_MAX_NVS_LENGTH },
+       [WL1251_NL_ATTR_NVS_LEN] =           { .type = NLA_U32 },
+       [WL1251_NL_ATTR_PLT_MODE] =          { .type = NLA_U32 },
+};
+
+static struct genl_ops wl1251_nl_ops[] = {
+       {
+               .cmd = WL1251_NL_CMD_TEST,
+               .doit = wl1251_nl_test_cmd,
+               .policy = wl1251_nl_policy,
+               .flags = GENL_ADMIN_PERM,
+       },
+       {
+               .cmd = WL1251_NL_CMD_INTERROGATE,
+               .doit = wl1251_nl_interrogate,
+               .policy = wl1251_nl_policy,
+               .flags = GENL_ADMIN_PERM,
+       },
+       {
+               .cmd = WL1251_NL_CMD_CONFIGURE,
+               .doit = wl1251_nl_configure,
+               .policy = wl1251_nl_policy,
+               .flags = GENL_ADMIN_PERM,
+       },
+       {
+               .cmd = WL1251_NL_CMD_PHY_REG_READ,
+               .doit = wl1251_nl_phy_reg_read,
+               .policy = wl1251_nl_policy,
+               .flags = GENL_ADMIN_PERM,
+       },
+       {
+               .cmd = WL1251_NL_CMD_NVS_PUSH,
+               .doit = wl1251_nl_nvs_push,
+               .policy = wl1251_nl_policy,
+               .flags = GENL_ADMIN_PERM,
+       },
+       {
+               .cmd = WL1251_NL_CMD_REG_WRITE,
+               .doit = wl1251_nl_reg_write,
+               .policy = wl1251_nl_policy,
+               .flags = GENL_ADMIN_PERM,
+       },
+       {
+               .cmd = WL1251_NL_CMD_REG_READ,
+               .doit = wl1251_nl_reg_read,
+               .policy = wl1251_nl_policy,
+               .flags = GENL_ADMIN_PERM,
+       },
+       {
+               .cmd = WL1251_NL_CMD_SET_PLT_MODE,
+               .doit = wl1251_nl_set_plt_mode,
+               .policy = wl1251_nl_policy,
+               .flags = GENL_ADMIN_PERM,
+       },
+};
+
+int wl1251_nl_register(void)
+{
+       int err, i;
+
+       err = genl_register_family(&wl1251_nl_family);
+       if (err)
+               return err;
+
+       for (i = 0; i < ARRAY_SIZE(wl1251_nl_ops); i++) {
+               err = genl_register_ops(&wl1251_nl_family, &wl1251_nl_ops[i]);
+               if (err)
+                       goto err_out;
+       }
+       return 0;
+ err_out:
+       genl_unregister_family(&wl1251_nl_family);
+       return err;
+}
+
+void wl1251_nl_unregister(void)
+{
+       genl_unregister_family(&wl1251_nl_family);
+}
diff --git a/drivers/net/wireless/wl12xx/wl1251_netlink.h b/drivers/net/wireless/wl12xx/wl1251_netlink.h
new file mode 100644 (file)
index 0000000..ee36695
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * This file is part of wl1251
+ *
+ * Copyright (C) 2009 Nokia Corporation
+ *
+ * Contact: Kalle Valo <kalle.valo@nokia.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 St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __WL1251_NETLINK_H__
+#define __WL1251_NETLINK_H__
+
+int wl1251_nl_register(void);
+void wl1251_nl_unregister(void);
+
+#endif /* __WL1251_NETLINK_H__ */
similarity index 66%
rename from drivers/net/wireless/wl12xx/wl1251.c
rename to drivers/net/wireless/wl12xx/wl1251_ops.c
index ce1561a..96a45f5 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * This file is part of wl12xx
+ * This file is part of wl1251
  *
  * Copyright (C) 2008-2009 Nokia Corporation
  *
 #include <linux/kernel.h>
 #include <linux/module.h>
 
-#include "wl1251.h"
+#include "wl1251_ops.h"
 #include "reg.h"
-#include "spi.h"
-#include "boot.h"
-#include "event.h"
-#include "acx.h"
-#include "tx.h"
-#include "rx.h"
-#include "ps.h"
-#include "init.h"
-
-static struct wl12xx_partition_set wl1251_part_table[PART_TABLE_LEN] = {
+#include "wl1251_spi.h"
+#include "wl1251_boot.h"
+#include "wl1251_event.h"
+#include "wl1251_acx.h"
+#include "wl1251_tx.h"
+#include "wl1251_rx.h"
+#include "wl1251_ps.h"
+#include "wl1251_init.h"
+
+static struct wl1251_partition_set wl1251_part_table[PART_TABLE_LEN] = {
        [PART_DOWN] = {
                .mem = {
                        .start = 0x00000000,
@@ -75,31 +75,31 @@ static enum wl12xx_acx_int_reg wl1251_acx_reg_table[ACX_REG_TABLE_LEN] = {
        [ACX_REG_ECPU_CONTROL]       = (REGISTERS_BASE + 0x0804)
 };
 
-static int wl1251_upload_firmware(struct wl12xx *wl)
+static int wl1251_upload_firmware(struct wl1251 *wl)
 {
-       struct wl12xx_partition_set *p_table = wl->chip.p_table;
+       struct wl1251_partition_set *p_table = wl->chip.p_table;
        int addr, chunk_num, partition_limit;
        size_t fw_data_len;
        u8 *p;
 
        /* whal_FwCtrl_LoadFwImageSm() */
 
-       wl12xx_debug(DEBUG_BOOT, "chip id before fw upload: 0x%x",
-                    wl12xx_reg_read32(wl, CHIP_ID_B));
+       wl1251_debug(DEBUG_BOOT, "chip id before fw upload: 0x%x",
+                    wl1251_reg_read32(wl, CHIP_ID_B));
 
        /* 10.0 check firmware length and set partition */
        fw_data_len =  (wl->fw[4] << 24) | (wl->fw[5] << 16) |
                (wl->fw[6] << 8) | (wl->fw[7]);
 
-       wl12xx_debug(DEBUG_BOOT, "fw_data_len %zu chunk_size %d", fw_data_len,
+       wl1251_debug(DEBUG_BOOT, "fw_data_len %zu chunk_size %d", fw_data_len,
                CHUNK_SIZE);
 
        if ((fw_data_len % 4) != 0) {
-               wl12xx_error("firmware length not multiple of four");
+               wl1251_error("firmware length not multiple of four");
                return -EIO;
        }
 
-       wl12xx_set_partition(wl,
+       wl1251_set_partition(wl,
                             p_table[PART_DOWN].mem.start,
                             p_table[PART_DOWN].mem.size,
                             p_table[PART_DOWN].reg.start,
@@ -118,7 +118,7 @@ static int wl1251_upload_firmware(struct wl12xx *wl)
                                chunk_num * CHUNK_SIZE;
                        partition_limit = chunk_num * CHUNK_SIZE +
                                p_table[PART_DOWN].mem.size;
-                       wl12xx_set_partition(wl,
+                       wl1251_set_partition(wl,
                                             addr,
                                             p_table[PART_DOWN].mem.size,
                                             p_table[PART_DOWN].reg.start,
@@ -128,9 +128,9 @@ static int wl1251_upload_firmware(struct wl12xx *wl)
                /* 10.3 upload the chunk */
                addr = p_table[PART_DOWN].mem.start + chunk_num * CHUNK_SIZE;
                p = wl->fw + FW_HDR_SIZE + chunk_num * CHUNK_SIZE;
-               wl12xx_debug(DEBUG_BOOT, "uploading fw chunk 0x%p to 0x%x",
+               wl1251_debug(DEBUG_BOOT, "uploading fw chunk 0x%p to 0x%x",
                             p, addr);
-               wl12xx_spi_mem_write(wl, addr, p, CHUNK_SIZE);
+               wl1251_spi_mem_write(wl, addr, p, CHUNK_SIZE);
 
                chunk_num++;
        }
@@ -138,14 +138,14 @@ static int wl1251_upload_firmware(struct wl12xx *wl)
        /* 10.4 upload the last chunk */
        addr = p_table[PART_DOWN].mem.start + chunk_num * CHUNK_SIZE;
        p = wl->fw + FW_HDR_SIZE + chunk_num * CHUNK_SIZE;
-       wl12xx_debug(DEBUG_BOOT, "uploading fw last chunk (%zu B) 0x%p to 0x%x",
+       wl1251_debug(DEBUG_BOOT, "uploading fw last chunk (%zu B) 0x%p to 0x%x",
                     fw_data_len % CHUNK_SIZE, p, addr);
-       wl12xx_spi_mem_write(wl, addr, p, fw_data_len % CHUNK_SIZE);
+       wl1251_spi_mem_write(wl, addr, p, fw_data_len % CHUNK_SIZE);
 
        return 0;
 }
 
-static int wl1251_upload_nvs(struct wl12xx *wl)
+static int wl1251_upload_nvs(struct wl1251 *wl)
 {
        size_t nvs_len, nvs_bytes_written, burst_len;
        int nvs_start, i;
@@ -181,10 +181,10 @@ static int wl1251_upload_nvs(struct wl12xx *wl)
                        val = (nvs_ptr[0] | (nvs_ptr[1] << 8)
                               | (nvs_ptr[2] << 16) | (nvs_ptr[3] << 24));
 
-                       wl12xx_debug(DEBUG_BOOT,
+                       wl1251_debug(DEBUG_BOOT,
                                     "nvs burst write 0x%x: 0x%x",
                                     dest_addr, val);
-                       wl12xx_mem_write32(wl, dest_addr, val);
+                       wl1251_mem_write32(wl, dest_addr, val);
 
                        nvs_ptr += 4;
                        dest_addr += 4;
@@ -200,7 +200,7 @@ static int wl1251_upload_nvs(struct wl12xx *wl)
        nvs_len = ALIGN(nvs_len, 4);
 
        /* Now we must set the partition correctly */
-       wl12xx_set_partition(wl, nvs_start,
+       wl1251_set_partition(wl, nvs_start,
                             wl->chip.p_table[PART_DOWN].mem.size,
                             wl->chip.p_table[PART_DOWN].reg.start,
                             wl->chip.p_table[PART_DOWN].reg.size);
@@ -213,10 +213,10 @@ static int wl1251_upload_nvs(struct wl12xx *wl)
 
                val = cpu_to_le32(val);
 
-               wl12xx_debug(DEBUG_BOOT,
+               wl1251_debug(DEBUG_BOOT,
                             "nvs write table 0x%x: 0x%x",
                             nvs_start, val);
-               wl12xx_mem_write32(wl, nvs_start, val);
+               wl1251_mem_write32(wl, nvs_start, val);
 
                nvs_ptr += 4;
                nvs_bytes_written += 4;
@@ -226,12 +226,12 @@ static int wl1251_upload_nvs(struct wl12xx *wl)
        return 0;
 }
 
-static int wl1251_boot(struct wl12xx *wl)
+static int wl1251_boot(struct wl1251 *wl)
 {
        int ret = 0, minor_minor_e2_ver;
        u32 tmp, boot_data;
 
-       ret = wl12xx_boot_soft_reset(wl);
+       ret = wl1251_boot_soft_reset(wl);
        if (ret < 0)
                goto out;
 
@@ -242,39 +242,39 @@ static int wl1251_boot(struct wl12xx *wl)
 
        /* write firmware's last address (ie. it's length) to
         * ACX_EEPROMLESS_IND_REG */
-       wl12xx_reg_write32(wl, ACX_EEPROMLESS_IND_REG, wl->fw_len);
+       wl1251_reg_write32(wl, ACX_EEPROMLESS_IND_REG, wl->fw_len);
 
        /* 6. read the EEPROM parameters */
-       tmp = wl12xx_reg_read32(wl, SCR_PAD2);
+       tmp = wl1251_reg_read32(wl, SCR_PAD2);
 
        /* 7. read bootdata */
        wl->boot_attr.radio_type = (tmp & 0x0000FF00) >> 8;
        wl->boot_attr.major = (tmp & 0x00FF0000) >> 16;
-       tmp = wl12xx_reg_read32(wl, SCR_PAD3);
+       tmp = wl1251_reg_read32(wl, SCR_PAD3);
 
        /* 8. check bootdata and call restart sequence */
        wl->boot_attr.minor = (tmp & 0x00FF0000) >> 16;
        minor_minor_e2_ver = (tmp & 0xFF000000) >> 24;
 
-       wl12xx_debug(DEBUG_BOOT, "radioType 0x%x majorE2Ver 0x%x "
+       wl1251_debug(DEBUG_BOOT, "radioType 0x%x majorE2Ver 0x%x "
                     "minorE2Ver 0x%x minor_minor_e2_ver 0x%x",
                     wl->boot_attr.radio_type, wl->boot_attr.major,
                     wl->boot_attr.minor, minor_minor_e2_ver);
 
-       ret = wl12xx_boot_init_seq(wl);
+       ret = wl1251_boot_init_seq(wl);
        if (ret < 0)
                goto out;
 
        /* 9. NVS processing done */
-       boot_data = wl12xx_reg_read32(wl, ACX_REG_ECPU_CONTROL);
+       boot_data = wl1251_reg_read32(wl, ACX_REG_ECPU_CONTROL);
 
-       wl12xx_debug(DEBUG_BOOT, "halt boot_data 0x%x", boot_data);
+       wl1251_debug(DEBUG_BOOT, "halt boot_data 0x%x", boot_data);
 
        /* 10. check that ECPU_CONTROL_HALT bits are set in
         * pWhalBus->uBootData and start uploading firmware
         */
        if ((boot_data & ECPU_CONTROL_HALT) == 0) {
-               wl12xx_error("boot failed, ECPU_CONTROL_HALT not set");
+               wl1251_error("boot failed, ECPU_CONTROL_HALT not set");
                ret = -EIO;
                goto out;
        }
@@ -284,62 +284,62 @@ static int wl1251_boot(struct wl12xx *wl)
                goto out;
 
        /* 10.5 start firmware */
-       ret = wl12xx_boot_run_firmware(wl);
+       ret = wl1251_boot_run_firmware(wl);
        if (ret < 0)
                goto out;
 
-       /* Get and save the firmware version */
-       wl12xx_acx_fw_version(wl, wl->chip.fw_ver, sizeof(wl->chip.fw_ver));
-
 out:
        return ret;
 }
 
-static int wl1251_mem_cfg(struct wl12xx *wl)
+static int wl1251_mem_cfg(struct wl1251 *wl)
 {
-       struct wl1251_acx_config_memory mem_conf;
+       struct wl1251_acx_config_memory *mem_conf;
        int ret, i;
 
-       wl12xx_debug(DEBUG_ACX, "wl1251 mem cfg");
+       wl1251_debug(DEBUG_ACX, "wl1251 mem cfg");
+
+       mem_conf = kzalloc(sizeof(*mem_conf), GFP_KERNEL);
+       if (!mem_conf) {
+               ret = -ENOMEM;
+               goto out;
+       }
 
        /* memory config */
-       mem_conf.mem_config.num_stations = cpu_to_le16(DEFAULT_NUM_STATIONS);
-       mem_conf.mem_config.rx_mem_block_num = 35;
-       mem_conf.mem_config.tx_min_mem_block_num = 64;
-       mem_conf.mem_config.num_tx_queues = MAX_TX_QUEUES;
-       mem_conf.mem_config.host_if_options = HOSTIF_PKT_RING;
-       mem_conf.mem_config.num_ssid_profiles = 1;
-       mem_conf.mem_config.debug_buffer_size =
+       mem_conf->mem_config.num_stations = cpu_to_le16(DEFAULT_NUM_STATIONS);
+       mem_conf->mem_config.rx_mem_block_num = 35;
+       mem_conf->mem_config.tx_min_mem_block_num = 64;
+       mem_conf->mem_config.num_tx_queues = MAX_TX_QUEUES;
+       mem_conf->mem_config.host_if_options = HOSTIF_PKT_RING;
+       mem_conf->mem_config.num_ssid_profiles = 1;
+       mem_conf->mem_config.debug_buffer_size =
                cpu_to_le16(TRACE_BUFFER_MAX_SIZE);
 
        /* RX queue config */
-       mem_conf.rx_queue_config.dma_address = 0;
-       mem_conf.rx_queue_config.num_descs = ACX_RX_DESC_DEF;
-       mem_conf.rx_queue_config.priority = DEFAULT_RXQ_PRIORITY;
-       mem_conf.rx_queue_config.type = DEFAULT_RXQ_TYPE;
+       mem_conf->rx_queue_config.dma_address = 0;
+       mem_conf->rx_queue_config.num_descs = ACX_RX_DESC_DEF;
+       mem_conf->rx_queue_config.priority = DEFAULT_RXQ_PRIORITY;
+       mem_conf->rx_queue_config.type = DEFAULT_RXQ_TYPE;
 
        /* TX queue config */
        for (i = 0; i < MAX_TX_QUEUES; i++) {
-               mem_conf.tx_queue_config[i].num_descs = ACX_TX_DESC_DEF;
-               mem_conf.tx_queue_config[i].attributes = i;
+               mem_conf->tx_queue_config[i].num_descs = ACX_TX_DESC_DEF;
+               mem_conf->tx_queue_config[i].attributes = i;
        }
 
-       mem_conf.header.id = ACX_MEM_CFG;
-       mem_conf.header.len = sizeof(struct wl1251_acx_config_memory) -
-               sizeof(struct acx_header);
-       mem_conf.header.len -=
-               (MAX_TX_QUEUE_CONFIGS - mem_conf.mem_config.num_tx_queues) *
-               sizeof(struct wl1251_acx_tx_queue_config);
-
-       ret = wl12xx_cmd_configure(wl, &mem_conf,
-                                  sizeof(struct wl1251_acx_config_memory));
-       if (ret < 0)
-               wl12xx_warning("wl1251 mem config failed: %d", ret);
+       ret = wl1251_cmd_configure(wl, ACX_MEM_CFG, mem_conf,
+                                  sizeof(*mem_conf));
+       if (ret < 0) {
+               wl1251_warning("wl1251 mem config failed: %d", ret);
+               goto out;
+       }
 
+out:
+       kfree(mem_conf);
        return ret;
 }
 
-static int wl1251_hw_init_mem_config(struct wl12xx *wl)
+static int wl1251_hw_init_mem_config(struct wl1251 *wl)
 {
        int ret;
 
@@ -350,15 +350,15 @@ static int wl1251_hw_init_mem_config(struct wl12xx *wl)
        wl->target_mem_map = kzalloc(sizeof(struct wl1251_acx_mem_map),
                                          GFP_KERNEL);
        if (!wl->target_mem_map) {
-               wl12xx_error("couldn't allocate target memory map");
+               wl1251_error("couldn't allocate target memory map");
                return -ENOMEM;
        }
 
        /* we now ask for the firmware built memory map */
-       ret = wl12xx_acx_mem_map(wl, wl->target_mem_map,
+       ret = wl1251_acx_mem_map(wl, wl->target_mem_map,
                                 sizeof(struct wl1251_acx_mem_map));
        if (ret < 0) {
-               wl12xx_error("couldn't retrieve firmware memory map");
+               wl1251_error("couldn't retrieve firmware memory map");
                kfree(wl->target_mem_map);
                wl->target_mem_map = NULL;
                return ret;
@@ -367,19 +367,19 @@ static int wl1251_hw_init_mem_config(struct wl12xx *wl)
        return 0;
 }
 
-static void wl1251_set_ecpu_ctrl(struct wl12xx *wl, u32 flag)
+static void wl1251_set_ecpu_ctrl(struct wl1251 *wl, u32 flag)
 {
        u32 cpu_ctrl;
 
        /* 10.5.0 run the firmware (I) */
-       cpu_ctrl = wl12xx_reg_read32(wl, ACX_REG_ECPU_CONTROL);
+       cpu_ctrl = wl1251_reg_read32(wl, ACX_REG_ECPU_CONTROL);
 
        /* 10.5.1 run the firmware (II) */
        cpu_ctrl &= ~flag;
-       wl12xx_reg_write32(wl, ACX_REG_ECPU_CONTROL, cpu_ctrl);
+       wl1251_reg_write32(wl, ACX_REG_ECPU_CONTROL, cpu_ctrl);
 }
 
-static void wl1251_target_enable_interrupts(struct wl12xx *wl)
+static void wl1251_target_enable_interrupts(struct wl1251 *wl)
 {
        /* Enable target's interrupts */
        wl->intr_mask = WL1251_ACX_INTR_RX0_DATA |
@@ -388,52 +388,60 @@ static void wl1251_target_enable_interrupts(struct wl12xx *wl)
                WL1251_ACX_INTR_EVENT_A |
                WL1251_ACX_INTR_EVENT_B |
                WL1251_ACX_INTR_INIT_COMPLETE;
-       wl12xx_boot_target_enable_interrupts(wl);
+       wl1251_boot_target_enable_interrupts(wl);
+}
+
+static void wl1251_fw_version(struct wl1251 *wl)
+{
+       wl1251_acx_fw_version(wl, wl->chip.fw_ver, sizeof(wl->chip.fw_ver));
 }
 
 static void wl1251_irq_work(struct work_struct *work)
 {
        u32 intr;
-       struct wl12xx *wl =
-               container_of(work, struct wl12xx, irq_work);
+       struct wl1251 *wl =
+               container_of(work, struct wl1251, irq_work);
+       int ret;
 
        mutex_lock(&wl->mutex);
 
-       wl12xx_debug(DEBUG_IRQ, "IRQ work");
+       wl1251_debug(DEBUG_IRQ, "IRQ work");
 
-       if (wl->state == WL12XX_STATE_OFF)
+       if (wl->state == WL1251_STATE_OFF)
                goto out;
 
-       wl12xx_ps_elp_wakeup(wl);
+       ret = wl1251_ps_elp_wakeup(wl);
+       if (ret < 0)
+               goto out;
 
-       wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_MASK, WL1251_ACX_INTR_ALL);
+       wl1251_reg_write32(wl, ACX_REG_INTERRUPT_MASK, WL1251_ACX_INTR_ALL);
 
-       intr = wl12xx_reg_read32(wl, ACX_REG_INTERRUPT_CLEAR);
-       wl12xx_debug(DEBUG_IRQ, "intr: 0x%x", intr);
+       intr = wl1251_reg_read32(wl, ACX_REG_INTERRUPT_CLEAR);
+       wl1251_debug(DEBUG_IRQ, "intr: 0x%x", intr);
 
        if (wl->data_path) {
-               wl12xx_spi_mem_read(wl, wl->data_path->rx_control_addr,
-                                   &wl->rx_counter, sizeof(u32));
+               wl->rx_counter =
+                       wl1251_mem_read32(wl, wl->data_path->rx_control_addr);
 
                /* We handle a frmware bug here */
                switch ((wl->rx_counter - wl->rx_handled) & 0xf) {
                case 0:
-                       wl12xx_debug(DEBUG_IRQ, "RX: FW and host in sync");
+                       wl1251_debug(DEBUG_IRQ, "RX: FW and host in sync");
                        intr &= ~WL1251_ACX_INTR_RX0_DATA;
                        intr &= ~WL1251_ACX_INTR_RX1_DATA;
                        break;
                case 1:
-                       wl12xx_debug(DEBUG_IRQ, "RX: FW +1");
+                       wl1251_debug(DEBUG_IRQ, "RX: FW +1");
                        intr |= WL1251_ACX_INTR_RX0_DATA;
                        intr &= ~WL1251_ACX_INTR_RX1_DATA;
                        break;
                case 2:
-                       wl12xx_debug(DEBUG_IRQ, "RX: FW +2");
+                       wl1251_debug(DEBUG_IRQ, "RX: FW +2");
                        intr |= WL1251_ACX_INTR_RX0_DATA;
                        intr |= WL1251_ACX_INTR_RX1_DATA;
                        break;
                default:
-                       wl12xx_warning("RX: FW and host out of sync: %d",
+                       wl1251_warning("RX: FW and host out of sync: %d",
                                       wl->rx_counter - wl->rx_handled);
                        break;
                }
@@ -441,49 +449,50 @@ static void wl1251_irq_work(struct work_struct *work)
                wl->rx_handled = wl->rx_counter;
 
 
-               wl12xx_debug(DEBUG_IRQ, "RX counter: %d", wl->rx_counter);
+               wl1251_debug(DEBUG_IRQ, "RX counter: %d", wl->rx_counter);
        }
 
        intr &= wl->intr_mask;
 
        if (intr == 0) {
-               wl12xx_debug(DEBUG_IRQ, "INTR is 0");
-               wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_MASK,
+               wl1251_debug(DEBUG_IRQ, "INTR is 0");
+               wl1251_reg_write32(wl, ACX_REG_INTERRUPT_MASK,
                                   ~(wl->intr_mask));
 
                goto out_sleep;
        }
 
        if (intr & WL1251_ACX_INTR_RX0_DATA) {
-               wl12xx_debug(DEBUG_IRQ, "WL1251_ACX_INTR_RX0_DATA");
-               wl12xx_rx(wl);
+               wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_RX0_DATA");
+               wl1251_rx(wl);
        }
 
        if (intr & WL1251_ACX_INTR_RX1_DATA) {
-               wl12xx_debug(DEBUG_IRQ, "WL1251_ACX_INTR_RX1_DATA");
-               wl12xx_rx(wl);
+               wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_RX1_DATA");
+               wl1251_rx(wl);
        }
 
        if (intr & WL1251_ACX_INTR_TX_RESULT) {
-               wl12xx_debug(DEBUG_IRQ, "WL1251_ACX_INTR_TX_RESULT");
-               wl12xx_tx_complete(wl);
+               wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_TX_RESULT");
+               wl1251_tx_complete(wl);
        }
 
        if (intr & (WL1251_ACX_INTR_EVENT_A | WL1251_ACX_INTR_EVENT_B)) {
-               wl12xx_debug(DEBUG_IRQ, "WL1251_ACX_INTR_EVENT (0x%x)", intr);
+               wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_EVENT (0x%x)", intr);
                if (intr & WL1251_ACX_INTR_EVENT_A)
-                       wl12xx_event_handle(wl, 0);
+                       wl1251_event_handle(wl, 0);
                else
-                       wl12xx_event_handle(wl, 1);
+                       wl1251_event_handle(wl, 1);
        }
 
        if (intr & WL1251_ACX_INTR_INIT_COMPLETE)
-               wl12xx_debug(DEBUG_IRQ, "WL1251_ACX_INTR_INIT_COMPLETE");
+               wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_INIT_COMPLETE");
 
-       wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_MASK, ~(wl->intr_mask));
+       wl1251_reg_write32(wl, ACX_REG_INTERRUPT_MASK, ~(wl->intr_mask));
 
 out_sleep:
-       wl12xx_ps_elp_sleep(wl);
+       wl1251_ps_elp_sleep(wl);
+
 out:
        mutex_unlock(&wl->mutex);
 }
@@ -520,40 +529,45 @@ static int wl1251_hw_init_txq_fill(u8 qid,
                        (QOS_TX_LOW_VO_DEF * num_blocks) / 100;
                break;
        default:
-               wl12xx_error("Invalid TX queue id: %d", qid);
+               wl1251_error("Invalid TX queue id: %d", qid);
                return -EINVAL;
        }
 
        return 0;
 }
 
-static int wl1251_hw_init_tx_queue_config(struct wl12xx *wl)
+static int wl1251_hw_init_tx_queue_config(struct wl1251 *wl)
 {
-       struct acx_tx_queue_qos_config config;
+       struct acx_tx_queue_qos_config *config;
        struct wl1251_acx_mem_map *wl_mem_map = wl->target_mem_map;
        int ret, i;
 
-       wl12xx_debug(DEBUG_ACX, "acx tx queue config");
+       wl1251_debug(DEBUG_ACX, "acx tx queue config");
 
-       config.header.id = ACX_TX_QUEUE_CFG;
-       config.header.len = sizeof(struct acx_tx_queue_qos_config) -
-               sizeof(struct acx_header);
+       config = kzalloc(sizeof(*config), GFP_KERNEL);
+       if (!config) {
+               ret = -ENOMEM;
+               goto out;
+       }
 
        for (i = 0; i < MAX_NUM_OF_AC; i++) {
-               ret = wl1251_hw_init_txq_fill(i, &config,
+               ret = wl1251_hw_init_txq_fill(i, config,
                                              wl_mem_map->num_tx_mem_blocks);
                if (ret < 0)
-                       return ret;
+                       goto out;
 
-               ret = wl12xx_cmd_configure(wl, &config, sizeof(config));
+               ret = wl1251_cmd_configure(wl, ACX_TX_QUEUE_CFG,
+                                          config, sizeof(*config));
                if (ret < 0)
-                       return ret;
+                       goto out;
        }
 
-       return 0;
+out:
+       kfree(config);
+       return ret;
 }
 
-static int wl1251_hw_init_data_path_config(struct wl12xx *wl)
+static int wl1251_hw_init_data_path_config(struct wl1251 *wl)
 {
        int ret;
 
@@ -561,11 +575,11 @@ static int wl1251_hw_init_data_path_config(struct wl12xx *wl)
        wl->data_path = kzalloc(sizeof(struct acx_data_path_params_resp),
                                GFP_KERNEL);
        if (!wl->data_path) {
-               wl12xx_error("Couldnt allocate data path parameters");
+               wl1251_error("Couldnt allocate data path parameters");
                return -ENOMEM;
        }
 
-       ret = wl12xx_acx_data_path_params(wl, wl->data_path);
+       ret = wl1251_acx_data_path_params(wl, wl->data_path);
        if (ret < 0) {
                kfree(wl->data_path);
                wl->data_path = NULL;
@@ -575,17 +589,17 @@ static int wl1251_hw_init_data_path_config(struct wl12xx *wl)
        return 0;
 }
 
-static int wl1251_hw_init(struct wl12xx *wl)
+static int wl1251_hw_init(struct wl1251 *wl)
 {
        struct wl1251_acx_mem_map *wl_mem_map;
        int ret;
 
-       ret = wl12xx_hw_init_hwenc_config(wl);
+       ret = wl1251_hw_init_hwenc_config(wl);
        if (ret < 0)
                return ret;
 
        /* Template settings */
-       ret = wl12xx_hw_init_templates_config(wl);
+       ret = wl1251_hw_init_templates_config(wl);
        if (ret < 0)
                return ret;
 
@@ -600,7 +614,7 @@ static int wl1251_hw_init(struct wl12xx *wl)
                goto out_free_memmap;
 
        /* RX config */
-       ret = wl12xx_hw_init_rx_config(wl,
+       ret = wl1251_hw_init_rx_config(wl,
                                       RX_CFG_PROMISCUOUS | RX_CFG_TSF,
                                       RX_FILTER_OPTION_DEF);
        /* RX_CONFIG_OPTION_ANY_DST_ANY_BSS,
@@ -614,42 +628,42 @@ static int wl1251_hw_init(struct wl12xx *wl)
                goto out_free_data_path;
 
        /* PHY layer config */
-       ret = wl12xx_hw_init_phy_config(wl);
+       ret = wl1251_hw_init_phy_config(wl);
        if (ret < 0)
                goto out_free_data_path;
 
        /* Beacon filtering */
-       ret = wl12xx_hw_init_beacon_filter(wl);
+       ret = wl1251_hw_init_beacon_filter(wl);
        if (ret < 0)
                goto out_free_data_path;
 
        /* Bluetooth WLAN coexistence */
-       ret = wl12xx_hw_init_pta(wl);
+       ret = wl1251_hw_init_pta(wl);
        if (ret < 0)
                goto out_free_data_path;
 
        /* Energy detection */
-       ret = wl12xx_hw_init_energy_detection(wl);
+       ret = wl1251_hw_init_energy_detection(wl);
        if (ret < 0)
                goto out_free_data_path;
 
        /* Beacons and boradcast settings */
-       ret = wl12xx_hw_init_beacon_broadcast(wl);
+       ret = wl1251_hw_init_beacon_broadcast(wl);
        if (ret < 0)
                goto out_free_data_path;
 
        /* Enable data path */
-       ret = wl12xx_cmd_data_path(wl, wl->channel, 1);
+       ret = wl1251_cmd_data_path(wl, wl->channel, 1);
        if (ret < 0)
                goto out_free_data_path;
 
        /* Default power state */
-       ret = wl12xx_hw_init_power_auth(wl);
+       ret = wl1251_hw_init_power_auth(wl);
        if (ret < 0)
                goto out_free_data_path;
 
        wl_mem_map = wl->target_mem_map;
-       wl12xx_info("%d tx blocks at 0x%x, %d rx blocks at 0x%x",
+       wl1251_info("%d tx blocks at 0x%x, %d rx blocks at 0x%x",
                    wl_mem_map->num_tx_mem_blocks,
                    wl->data_path->tx_control_addr,
                    wl_mem_map->num_rx_mem_blocks,
@@ -666,7 +680,7 @@ static int wl1251_hw_init(struct wl12xx *wl)
        return ret;
 }
 
-static int wl1251_plt_init(struct wl12xx *wl)
+static int wl1251_plt_init(struct wl1251 *wl)
 {
        int ret;
 
@@ -674,14 +688,14 @@ static int wl1251_plt_init(struct wl12xx *wl)
        if (ret < 0)
                return ret;
 
-       ret = wl12xx_cmd_data_path(wl, wl->channel, 1);
+       ret = wl1251_cmd_data_path(wl, wl->channel, 1);
        if (ret < 0)
                return ret;
 
        return 0;
 }
 
-void wl1251_setup(struct wl12xx *wl)
+void wl1251_setup(struct wl1251 *wl)
 {
        /* FIXME: Is it better to use strncpy here or is this ok? */
        wl->chip.fw_filename = WL1251_FW_NAME;
@@ -701,9 +715,14 @@ void wl1251_setup(struct wl12xx *wl)
        wl->chip.op_target_enable_interrupts = wl1251_target_enable_interrupts;
        wl->chip.op_hw_init = wl1251_hw_init;
        wl->chip.op_plt_init = wl1251_plt_init;
+       wl->chip.op_fw_version = wl1251_fw_version;
+       wl->chip.op_tx_flush = wl1251_tx_flush;
+       wl->chip.op_cmd_join = wl1251_cmd_join;
 
        wl->chip.p_table = wl1251_part_table;
        wl->chip.acx_reg_table = wl1251_acx_reg_table;
 
        INIT_WORK(&wl->irq_work, wl1251_irq_work);
+       INIT_WORK(&wl->tx_work, wl1251_tx_work);
+
 }
diff --git a/drivers/net/wireless/wl12xx/wl1251_ops.h b/drivers/net/wireless/wl12xx/wl1251_ops.h
new file mode 100644 (file)
index 0000000..68183c4
--- /dev/null
@@ -0,0 +1,165 @@
+/*
+ * This file is part of wl1251
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ *
+ * Contact: Kalle Valo <kalle.valo@nokia.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 St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __WL1251_OPS_H__
+#define __WL1251_OPS_H__
+
+#include <linux/bitops.h>
+
+#include "wl1251.h"
+#include "wl1251_acx.h"
+
+#define WL1251_FW_NAME "wl1251-fw.bin"
+#define WL1251_NVS_NAME "wl1251-nvs.bin"
+
+#define WL1251_POWER_ON_SLEEP 10 /* in miliseconds */
+
+void wl1251_setup(struct wl1251 *wl);
+
+
+struct wl1251_acx_memory {
+       __le16 num_stations; /* number of STAs to be supported. */
+       u16 reserved_1;
+
+       /*
+        * Nmber of memory buffers for the RX mem pool.
+        * The actual number may be less if there are
+        * not enough blocks left for the minimum num
+        * of TX ones.
+        */
+       u8 rx_mem_block_num;
+       u8 reserved_2;
+       u8 num_tx_queues; /* From 1 to 16 */
+       u8 host_if_options; /* HOST_IF* */
+       u8 tx_min_mem_block_num;
+       u8 num_ssid_profiles;
+       __le16 debug_buffer_size;
+} __attribute__ ((packed));
+
+
+#define ACX_RX_DESC_MIN                1
+#define ACX_RX_DESC_MAX                127
+#define ACX_RX_DESC_DEF                32
+struct wl1251_acx_rx_queue_config {
+       u8 num_descs;
+       u8 pad;
+       u8 type;
+       u8 priority;
+       __le32 dma_address;
+} __attribute__ ((packed));
+
+#define ACX_TX_DESC_MIN                1
+#define ACX_TX_DESC_MAX                127
+#define ACX_TX_DESC_DEF                16
+struct wl1251_acx_tx_queue_config {
+    u8 num_descs;
+    u8 pad[2];
+    u8 attributes;
+} __attribute__ ((packed));
+
+#define MAX_TX_QUEUE_CONFIGS 5
+#define MAX_TX_QUEUES 4
+struct wl1251_acx_config_memory {
+       struct acx_header header;
+
+       struct wl1251_acx_memory mem_config;
+       struct wl1251_acx_rx_queue_config rx_queue_config;
+       struct wl1251_acx_tx_queue_config tx_queue_config[MAX_TX_QUEUE_CONFIGS];
+} __attribute__ ((packed));
+
+struct wl1251_acx_mem_map {
+       struct acx_header header;
+
+       void *code_start;
+       void *code_end;
+
+       void *wep_defkey_start;
+       void *wep_defkey_end;
+
+       void *sta_table_start;
+       void *sta_table_end;
+
+       void *packet_template_start;
+       void *packet_template_end;
+
+       void *queue_memory_start;
+       void *queue_memory_end;
+
+       void *packet_memory_pool_start;
+       void *packet_memory_pool_end;
+
+       void *debug_buffer1_start;
+       void *debug_buffer1_end;
+
+       void *debug_buffer2_start;
+       void *debug_buffer2_end;
+
+       /* Number of blocks FW allocated for TX packets */
+       u32 num_tx_mem_blocks;
+
+       /* Number of blocks FW allocated for RX packets */
+       u32 num_rx_mem_blocks;
+} __attribute__ ((packed));
+
+/*************************************************************************
+
+    Host Interrupt Register (WiLink -> Host)
+
+**************************************************************************/
+
+/* RX packet is ready in Xfer buffer #0 */
+#define WL1251_ACX_INTR_RX0_DATA      BIT(0)
+
+/* TX result(s) are in the TX complete buffer */
+#define WL1251_ACX_INTR_TX_RESULT      BIT(1)
+
+/* OBSOLETE */
+#define WL1251_ACX_INTR_TX_XFR         BIT(2)
+
+/* RX packet is ready in Xfer buffer #1 */
+#define WL1251_ACX_INTR_RX1_DATA       BIT(3)
+
+/* Event was entered to Event MBOX #A */
+#define WL1251_ACX_INTR_EVENT_A                BIT(4)
+
+/* Event was entered to Event MBOX #B */
+#define WL1251_ACX_INTR_EVENT_B                BIT(5)
+
+/* OBSOLETE */
+#define WL1251_ACX_INTR_WAKE_ON_HOST   BIT(6)
+
+/* Trace meassge on MBOX #A */
+#define WL1251_ACX_INTR_TRACE_A                BIT(7)
+
+/* Trace meassge on MBOX #B */
+#define WL1251_ACX_INTR_TRACE_B                BIT(8)
+
+/* Command processing completion */
+#define WL1251_ACX_INTR_CMD_COMPLETE   BIT(9)
+
+/* Init sequence is done */
+#define WL1251_ACX_INTR_INIT_COMPLETE  BIT(14)
+
+#define WL1251_ACX_INTR_ALL           0xFFFFFFFF
+
+#endif
similarity index 55%
rename from drivers/net/wireless/wl12xx/ps.c
rename to drivers/net/wireless/wl12xx/wl1251_ps.c
index 83a1011..68ff7f1 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * This file is part of wl12xx
+ * This file is part of wl1251
  *
  * Copyright (C) 2008 Nokia Corporation
  *
  */
 
 #include "reg.h"
-#include "ps.h"
-#include "spi.h"
+#include "wl1251_ps.h"
+#include "wl1251_spi.h"
 
-#define WL12XX_WAKEUP_TIMEOUT 2000
+#define WL1251_WAKEUP_TIMEOUT 2000
 
 /* Routines to toggle sleep mode while in ELP */
-void wl12xx_ps_elp_sleep(struct wl12xx *wl)
+void wl1251_ps_elp_sleep(struct wl1251 *wl)
 {
        if (wl->elp || !wl->psm)
                return;
 
-       wl12xx_debug(DEBUG_PSM, "chip to elp");
+       wl1251_debug(DEBUG_PSM, "chip to elp");
 
-       wl12xx_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_SLEEP);
+       wl1251_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_SLEEP);
 
        wl->elp = true;
 }
 
-int wl12xx_ps_elp_wakeup(struct wl12xx *wl)
+int wl1251_ps_elp_wakeup(struct wl1251 *wl)
 {
        unsigned long timeout;
        u32 elp_reg;
@@ -48,13 +48,13 @@ int wl12xx_ps_elp_wakeup(struct wl12xx *wl)
        if (!wl->elp)
                return 0;
 
-       wl12xx_debug(DEBUG_PSM, "waking up chip from elp");
+       wl1251_debug(DEBUG_PSM, "waking up chip from elp");
 
-       timeout = jiffies + msecs_to_jiffies(WL12XX_WAKEUP_TIMEOUT);
+       timeout = jiffies + msecs_to_jiffies(WL1251_WAKEUP_TIMEOUT);
 
-       wl12xx_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_WAKE_UP);
+       wl1251_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_WAKE_UP);
 
-       elp_reg = wl12xx_read32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR);
+       elp_reg = wl1251_read32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR);
 
        /*
         * FIXME: we should wait for irq from chip but, as a temporary
@@ -62,40 +62,36 @@ int wl12xx_ps_elp_wakeup(struct wl12xx *wl)
         */
        while (!(elp_reg & ELPCTRL_WLAN_READY)) {
                if (time_after(jiffies, timeout)) {
-                       wl12xx_error("elp wakeup timeout");
+                       wl1251_error("elp wakeup timeout");
                        return -ETIMEDOUT;
                }
                msleep(1);
-               elp_reg = wl12xx_read32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR);
+               elp_reg = wl1251_read32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR);
        }
 
-       wl12xx_debug(DEBUG_PSM, "wakeup time: %u ms",
+       wl1251_debug(DEBUG_PSM, "wakeup time: %u ms",
                     jiffies_to_msecs(jiffies) -
-                    (jiffies_to_msecs(timeout) - WL12XX_WAKEUP_TIMEOUT));
+                    (jiffies_to_msecs(timeout) - WL1251_WAKEUP_TIMEOUT));
 
        wl->elp = false;
 
        return 0;
 }
 
-static int wl12xx_ps_set_elp(struct wl12xx *wl, bool enable)
+static int wl1251_ps_set_elp(struct wl1251 *wl, bool enable)
 {
        int ret;
 
        if (enable) {
-               wl12xx_debug(DEBUG_PSM, "sleep auth psm/elp");
+               wl1251_debug(DEBUG_PSM, "sleep auth psm/elp");
 
-               /*
-                * FIXME: we should PSM_ELP, but because of firmware wakeup
-                * problems let's use only PSM_PS
-                */
-               ret = wl12xx_acx_sleep_auth(wl, WL12XX_PSM_PS);
+               ret = wl1251_acx_sleep_auth(wl, WL1251_PSM_ELP);
                if (ret < 0)
                        return ret;
 
-               wl12xx_ps_elp_sleep(wl);
+               wl1251_ps_elp_sleep(wl);
        } else {
-               wl12xx_debug(DEBUG_PSM, "sleep auth cam");
+               wl1251_debug(DEBUG_PSM, "sleep auth cam");
 
                /*
                 * When the target is in ELP, we can only
@@ -104,9 +100,9 @@ static int wl12xx_ps_set_elp(struct wl12xx *wl, bool enable)
                 * changing the power authorization.
                 */
 
-               wl12xx_ps_elp_wakeup(wl);
+               wl1251_ps_elp_wakeup(wl);
 
-               ret = wl12xx_acx_sleep_auth(wl, WL12XX_PSM_CAM);
+               ret = wl1251_acx_sleep_auth(wl, WL1251_PSM_CAM);
                if (ret < 0)
                        return ret;
        }
@@ -114,18 +110,18 @@ static int wl12xx_ps_set_elp(struct wl12xx *wl, bool enable)
        return 0;
 }
 
-int wl12xx_ps_set_mode(struct wl12xx *wl, enum acx_ps_mode mode)
+int wl1251_ps_set_mode(struct wl1251 *wl, enum wl1251_cmd_ps_mode mode)
 {
        int ret;
 
        switch (mode) {
        case STATION_POWER_SAVE_MODE:
-               wl12xx_debug(DEBUG_PSM, "entering psm");
-               ret = wl12xx_cmd_ps_mode(wl, STATION_POWER_SAVE_MODE);
+               wl1251_debug(DEBUG_PSM, "entering psm");
+               ret = wl1251_cmd_ps_mode(wl, STATION_POWER_SAVE_MODE);
                if (ret < 0)
                        return ret;
 
-               ret = wl12xx_ps_set_elp(wl, true);
+               ret = wl1251_ps_set_elp(wl, true);
                if (ret < 0)
                        return ret;
 
@@ -133,12 +129,12 @@ int wl12xx_ps_set_mode(struct wl12xx *wl, enum acx_ps_mode mode)
                break;
        case STATION_ACTIVE_MODE:
        default:
-               wl12xx_debug(DEBUG_PSM, "leaving psm");
-               ret = wl12xx_ps_set_elp(wl, false);
+               wl1251_debug(DEBUG_PSM, "leaving psm");
+               ret = wl1251_ps_set_elp(wl, false);
                if (ret < 0)
                        return ret;
 
-               ret = wl12xx_cmd_ps_mode(wl, STATION_ACTIVE_MODE);
+               ret = wl1251_cmd_ps_mode(wl, STATION_ACTIVE_MODE);
                if (ret < 0)
                        return ret;
 
similarity index 72%
rename from drivers/net/wireless/wl12xx/ps.h
rename to drivers/net/wireless/wl12xx/wl1251_ps.h
index 5d7c525..db036fe 100644 (file)
@@ -1,8 +1,8 @@
-#ifndef __WL12XX_PS_H__
-#define __WL12XX_PS_H__
+#ifndef __WL1251_PS_H__
+#define __WL1251_PS_H__
 
 /*
- * This file is part of wl12xx
+ * This file is part of wl1251
  *
  * Copyright (c) 1998-2007 Texas Instruments Incorporated
  * Copyright (C) 2008 Nokia Corporation
  *
  */
 
-#include "wl12xx.h"
-#include "acx.h"
+#include "wl1251.h"
+#include "wl1251_acx.h"
 
-int wl12xx_ps_set_mode(struct wl12xx *wl, enum acx_ps_mode mode);
-void wl12xx_ps_elp_sleep(struct wl12xx *wl);
-int wl12xx_ps_elp_wakeup(struct wl12xx *wl);
+int wl1251_ps_set_mode(struct wl1251 *wl, enum wl1251_cmd_ps_mode mode);
+void wl1251_ps_elp_sleep(struct wl1251 *wl);
+int wl1251_ps_elp_wakeup(struct wl1251 *wl);
 
 
-#endif /* __WL12XX_PS_H__ */
+#endif /* __WL1251_PS_H__ */
similarity index 68%
rename from drivers/net/wireless/wl12xx/rx.c
rename to drivers/net/wireless/wl12xx/wl1251_rx.c
index 981ea25..0dbb483 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * This file is part of wl12xx
+ * This file is part of wl1251
  *
  * Copyright (c) 1998-2007 Texas Instruments Incorporated
  * Copyright (C) 2008 Nokia Corporation
 #include <linux/skbuff.h>
 #include <net/mac80211.h>
 
-#include "wl12xx.h"
+#include "wl1251.h"
 #include "reg.h"
-#include "spi.h"
-#include "rx.h"
+#include "wl1251_spi.h"
+#include "wl1251_rx.h"
+#include "wl1251_acx.h"
 
-static void wl12xx_rx_header(struct wl12xx *wl,
-                            struct wl12xx_rx_descriptor *desc)
+static void wl1251_rx_header(struct wl1251 *wl,
+                            struct wl1251_rx_descriptor *desc)
 {
        u32 rx_packet_ring_addr;
 
@@ -39,15 +40,17 @@ static void wl12xx_rx_header(struct wl12xx *wl,
        if (wl->rx_current_buffer)
                rx_packet_ring_addr += wl->data_path->rx_packet_ring_chunk_size;
 
-       wl12xx_spi_mem_read(wl, rx_packet_ring_addr, desc,
-                           sizeof(struct wl12xx_rx_descriptor));
+       wl1251_spi_mem_read(wl, rx_packet_ring_addr, desc, sizeof(*desc));
 }
 
-static void wl12xx_rx_status(struct wl12xx *wl,
-                            struct wl12xx_rx_descriptor *desc,
+static void wl1251_rx_status(struct wl1251 *wl,
+                            struct wl1251_rx_descriptor *desc,
                             struct ieee80211_rx_status *status,
                             u8 beacon)
 {
+       u64 mactime;
+       int ret;
+
        memset(status, 0, sizeof(struct ieee80211_rx_status));
 
        status->band = IEEE80211_BAND_2GHZ;
@@ -62,32 +65,14 @@ static void wl12xx_rx_status(struct wl12xx *wl,
         * this one must be atomic, while our SPI routines can sleep.
         */
        if ((wl->bss_type == BSS_TYPE_IBSS) && beacon) {
-               u64 mactime;
-               int ret;
-               struct wl12xx_command cmd;
-               struct acx_tsf_info *tsf_info;
-
-               memset(&cmd, 0, sizeof(cmd));
-
-               ret = wl12xx_cmd_interrogate(wl, ACX_TSF_INFO,
-                                            sizeof(struct acx_tsf_info),
-                                            &cmd);
-               if (ret < 0) {
-                       wl12xx_warning("ACX_FW_REV interrogate failed");
-                       return;
-               }
-
-               tsf_info = (struct acx_tsf_info *)&(cmd.parameters);
-
-               mactime = tsf_info->current_tsf_lsb |
-                       (tsf_info->current_tsf_msb << 31);
-
-               status->mactime = mactime;
+               ret = wl1251_acx_tsf_info(wl, &mactime);
+               if (ret == 0)
+                       status->mactime = mactime;
        }
 
        status->signal = desc->rssi;
-       status->qual = (desc->rssi - WL12XX_RX_MIN_RSSI) * 100 /
-               (WL12XX_RX_MAX_RSSI - WL12XX_RX_MIN_RSSI);
+       status->qual = (desc->rssi - WL1251_RX_MIN_RSSI) * 100 /
+               (WL1251_RX_MAX_RSSI - WL1251_RX_MIN_RSSI);
        status->qual = min(status->qual, 100);
        status->qual = max(status->qual, 0);
 
@@ -118,8 +103,8 @@ static void wl12xx_rx_status(struct wl12xx *wl,
        /* FIXME: set status->rate_idx */
 }
 
-static void wl12xx_rx_body(struct wl12xx *wl,
-                          struct wl12xx_rx_descriptor *desc)
+static void wl1251_rx_body(struct wl1251 *wl,
+                          struct wl1251_rx_descriptor *desc)
 {
        struct sk_buff *skb;
        struct ieee80211_rx_status status;
@@ -127,12 +112,12 @@ static void wl12xx_rx_body(struct wl12xx *wl,
        u16 length, *fc;
        u32 curr_id, last_id_inc, rx_packet_ring_addr;
 
-       length = WL12XX_RX_ALIGN(desc->length  - PLCP_HEADER_LENGTH);
+       length = WL1251_RX_ALIGN(desc->length  - PLCP_HEADER_LENGTH);
        curr_id = (desc->flags & RX_DESC_SEQNUM_MASK) >> RX_DESC_PACKETID_SHIFT;
        last_id_inc = (wl->rx_last_id + 1) % (RX_MAX_PACKET_ID + 1);
 
        if (last_id_inc != curr_id) {
-               wl12xx_warning("curr ID:%d, last ID inc:%d",
+               wl1251_warning("curr ID:%d, last ID inc:%d",
                               curr_id, last_id_inc);
                wl->rx_last_id = curr_id;
        } else {
@@ -140,18 +125,18 @@ static void wl12xx_rx_body(struct wl12xx *wl,
        }
 
        rx_packet_ring_addr = wl->data_path->rx_packet_ring_addr +
-               sizeof(struct wl12xx_rx_descriptor) + 20;
+               sizeof(struct wl1251_rx_descriptor) + 20;
        if (wl->rx_current_buffer)
                rx_packet_ring_addr += wl->data_path->rx_packet_ring_chunk_size;
 
        skb = dev_alloc_skb(length);
        if (!skb) {
-               wl12xx_error("Couldn't allocate RX frame");
+               wl1251_error("Couldn't allocate RX frame");
                return;
        }
 
        rx_buffer = skb_put(skb, length);
-       wl12xx_spi_mem_read(wl, rx_packet_ring_addr, rx_buffer, length);
+       wl1251_spi_mem_read(wl, rx_packet_ring_addr, rx_buffer, length);
 
        /* The actual lenght doesn't include the target's alignment */
        skb->len = desc->length  - PLCP_HEADER_LENGTH;
@@ -161,15 +146,16 @@ static void wl12xx_rx_body(struct wl12xx *wl,
        if ((*fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BEACON)
                beacon = 1;
 
-       wl12xx_rx_status(wl, desc, &status, beacon);
+       wl1251_rx_status(wl, desc, &status, beacon);
 
-       wl12xx_debug(DEBUG_RX, "rx skb 0x%p: %d B %s", skb, skb->len,
+       wl1251_debug(DEBUG_RX, "rx skb 0x%p: %d B %s", skb, skb->len,
                     beacon ? "beacon" : "");
 
-       ieee80211_rx(wl->hw, skb, &status);
+       memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status));
+       ieee80211_rx(wl->hw, skb);
 }
 
-static void wl12xx_rx_ack(struct wl12xx *wl)
+static void wl1251_rx_ack(struct wl1251 *wl)
 {
        u32 data, addr;
 
@@ -181,28 +167,30 @@ static void wl12xx_rx_ack(struct wl12xx *wl)
                data = INTR_TRIG_RX_PROC0;
        }
 
-       wl12xx_reg_write32(wl, addr, data);
+       wl1251_reg_write32(wl, addr, data);
 
        /* Toggle buffer ring */
        wl->rx_current_buffer = !wl->rx_current_buffer;
 }
 
 
-void wl12xx_rx(struct wl12xx *wl)
+void wl1251_rx(struct wl1251 *wl)
 {
-       struct wl12xx_rx_descriptor rx_desc;
+       struct wl1251_rx_descriptor *rx_desc;
 
-       if (wl->state != WL12XX_STATE_ON)
+       if (wl->state != WL1251_STATE_ON)
                return;
 
+       rx_desc = wl->rx_descriptor;
+
        /* We first read the frame's header */
-       wl12xx_rx_header(wl, &rx_desc);
+       wl1251_rx_header(wl, rx_desc);
 
        /* Now we can read the body */
-       wl12xx_rx_body(wl, &rx_desc);
+       wl1251_rx_body(wl, rx_desc);
 
        /* Finally, we need to ACK the RX */
-       wl12xx_rx_ack(wl);
+       wl1251_rx_ack(wl);
 
        return;
 }
similarity index 89%
rename from drivers/net/wireless/wl12xx/rx.h
rename to drivers/net/wireless/wl12xx/wl1251_rx.h
index 8a23fde..81156b9 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * This file is part of wl12xx
+ * This file is part of wl1251
  *
  * Copyright (c) 1998-2007 Texas Instruments Incorporated
  * Copyright (C) 2008 Nokia Corporation
  *
  */
 
-#ifndef __WL12XX_RX_H__
-#define __WL12XX_RX_H__
+#ifndef __WL1251_RX_H__
+#define __WL1251_RX_H__
 
 #include <linux/bitops.h>
 
+#include "wl1251.h"
+
 /*
  * RX PATH
  *
  * 4) The target prepares the next RX packet.
  */
 
-#define WL12XX_RX_MAX_RSSI -30
-#define WL12XX_RX_MIN_RSSI -95
+#define WL1251_RX_MAX_RSSI -30
+#define WL1251_RX_MIN_RSSI -95
 
-#define WL12XX_RX_ALIGN_TO 4
-#define WL12XX_RX_ALIGN(len) (((len) + WL12XX_RX_ALIGN_TO - 1) & \
-                            ~(WL12XX_RX_ALIGN_TO - 1))
+#define WL1251_RX_ALIGN_TO 4
+#define WL1251_RX_ALIGN(len) (((len) + WL1251_RX_ALIGN_TO - 1) & \
+                            ~(WL1251_RX_ALIGN_TO - 1))
 
 #define SHORT_PREAMBLE_BIT   BIT(0)
 #define OFDM_RATE_BIT        BIT(6)
@@ -72,7 +74,7 @@
 #define        RX_DESC_MIC_FAIL          0x2000
 #define        RX_DESC_DECRYPT_FAIL      0x4000
 
-struct wl12xx_rx_descriptor {
+struct wl1251_rx_descriptor {
        u32 timestamp; /* In microseconds */
        u16 length; /* Paylod length, including headers */
        u16 flags;
@@ -117,6 +119,6 @@ struct wl12xx_rx_descriptor {
        u8 snr; /* in dB */
 } __attribute__ ((packed));
 
-void wl12xx_rx(struct wl12xx *wl);
+void wl1251_rx(struct wl1251 *wl);
 
 #endif
similarity index 63%
rename from drivers/net/wireless/wl12xx/spi.c
rename to drivers/net/wireless/wl12xx/wl1251_spi.c
index abdf171..c5da79d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * This file is part of wl12xx
+ * This file is part of wl1251
  *
  * Copyright (C) 2008 Nokia Corporation
  *
 #include <linux/crc7.h>
 #include <linux/spi/spi.h>
 
-#include "wl12xx.h"
-#include "wl12xx_80211.h"
+#include "wl1251.h"
 #include "reg.h"
-#include "spi.h"
-#include "ps.h"
+#include "wl1251_spi.h"
 
-static int wl12xx_translate_reg_addr(struct wl12xx *wl, int addr)
+static int wl1251_translate_reg_addr(struct wl1251 *wl, int addr)
 {
        /* If the address is lower than REGISTERS_BASE, it means that this is
         * a chip-specific register address, so look it up in the registers
@@ -39,7 +37,7 @@ static int wl12xx_translate_reg_addr(struct wl12xx *wl, int addr)
        if (addr < REGISTERS_BASE) {
                /* Make sure we don't go over the table */
                if (addr >= ACX_REG_TABLE_LEN) {
-                       wl12xx_error("address out of range (%d)", addr);
+                       wl1251_error("address out of range (%d)", addr);
                        return -EINVAL;
                }
                addr = wl->chip.acx_reg_table[addr];
@@ -48,13 +46,13 @@ static int wl12xx_translate_reg_addr(struct wl12xx *wl, int addr)
        return addr - wl->physical_reg_addr + wl->virtual_reg_addr;
 }
 
-static int wl12xx_translate_mem_addr(struct wl12xx *wl, int addr)
+static int wl1251_translate_mem_addr(struct wl1251 *wl, int addr)
 {
        return addr - wl->physical_mem_addr + wl->virtual_mem_addr;
 }
 
 
-void wl12xx_spi_reset(struct wl12xx *wl)
+void wl1251_spi_reset(struct wl1251 *wl)
 {
        u8 *cmd;
        struct spi_transfer t;
@@ -62,7 +60,7 @@ void wl12xx_spi_reset(struct wl12xx *wl)
 
        cmd = kzalloc(WSPI_INIT_CMD_LEN, GFP_KERNEL);
        if (!cmd) {
-               wl12xx_error("could not allocate cmd for spi reset");
+               wl1251_error("could not allocate cmd for spi reset");
                return;
        }
 
@@ -77,10 +75,10 @@ void wl12xx_spi_reset(struct wl12xx *wl)
 
        spi_sync(wl->spi, &m);
 
-       wl12xx_dump(DEBUG_SPI, "spi reset -> ", cmd, WSPI_INIT_CMD_LEN);
+       wl1251_dump(DEBUG_SPI, "spi reset -> ", cmd, WSPI_INIT_CMD_LEN);
 }
 
-void wl12xx_spi_init(struct wl12xx *wl)
+void wl1251_spi_init(struct wl1251 *wl)
 {
        u8 crc[WSPI_INIT_CMD_CRC_LEN], *cmd;
        struct spi_transfer t;
@@ -88,7 +86,7 @@ void wl12xx_spi_init(struct wl12xx *wl)
 
        cmd = kzalloc(WSPI_INIT_CMD_LEN, GFP_KERNEL);
        if (!cmd) {
-               wl12xx_error("could not allocate cmd for spi init");
+               wl1251_error("could not allocate cmd for spi init");
                return;
        }
 
@@ -131,7 +129,7 @@ void wl12xx_spi_init(struct wl12xx *wl)
 
        spi_sync(wl->spi, &m);
 
-       wl12xx_dump(DEBUG_SPI, "spi init -> ", cmd, WSPI_INIT_CMD_LEN);
+       wl1251_dump(DEBUG_SPI, "spi init -> ", cmd, WSPI_INIT_CMD_LEN);
 }
 
 /* Set the SPI partitions to access the chip addresses
@@ -167,45 +165,47 @@ void wl12xx_spi_init(struct wl12xx *wl)
  *                                    |    |
  *
  */
-void wl12xx_set_partition(struct wl12xx *wl,
+int wl1251_set_partition(struct wl1251 *wl,
                          u32 mem_start, u32 mem_size,
                          u32 reg_start, u32 reg_size)
 {
-       u8 tx_buf[sizeof(u32) + 2 * sizeof(struct wl12xx_partition)];
-       struct wl12xx_partition *partition;
+       struct wl1251_partition *partition;
        struct spi_transfer t;
        struct spi_message m;
+       size_t len, cmd_len;
        u32 *cmd;
-       size_t len;
        int addr;
 
+       cmd_len = sizeof(u32) + 2 * sizeof(struct wl1251_partition);
+       cmd = kzalloc(cmd_len, GFP_KERNEL);
+       if (!cmd)
+               return -ENOMEM;
+
        spi_message_init(&m);
        memset(&t, 0, sizeof(t));
-       memset(tx_buf, 0, sizeof(tx_buf));
 
-       cmd = (u32 *) tx_buf;
-       partition = (struct wl12xx_partition *) (tx_buf + sizeof(u32));
+       partition = (struct wl1251_partition *) (cmd + 1);
        addr = HW_ACCESS_PART0_SIZE_ADDR;
-       len = 2 * sizeof(struct wl12xx_partition);
+       len = 2 * sizeof(struct wl1251_partition);
 
        *cmd |= WSPI_CMD_WRITE;
        *cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH;
        *cmd |= addr & WSPI_CMD_BYTE_ADDR;
 
-       wl12xx_debug(DEBUG_SPI, "mem_start %08X mem_size %08X",
+       wl1251_debug(DEBUG_SPI, "mem_start %08X mem_size %08X",
                     mem_start, mem_size);
-       wl12xx_debug(DEBUG_SPI, "reg_start %08X reg_size %08X",
+       wl1251_debug(DEBUG_SPI, "reg_start %08X reg_size %08X",
                     reg_start, reg_size);
 
        /* Make sure that the two partitions together don't exceed the
         * address range */
        if ((mem_size + reg_size) > HW_ACCESS_MEMORY_MAX_RANGE) {
-               wl12xx_debug(DEBUG_SPI, "Total size exceeds maximum virtual"
+               wl1251_debug(DEBUG_SPI, "Total size exceeds maximum virtual"
                             " address range.  Truncating partition[0].");
                mem_size = HW_ACCESS_MEMORY_MAX_RANGE - reg_size;
-               wl12xx_debug(DEBUG_SPI, "mem_start %08X mem_size %08X",
+               wl1251_debug(DEBUG_SPI, "mem_start %08X mem_size %08X",
                             mem_start, mem_size);
-               wl12xx_debug(DEBUG_SPI, "reg_start %08X reg_size %08X",
+               wl1251_debug(DEBUG_SPI, "reg_start %08X reg_size %08X",
                             reg_start, reg_size);
        }
 
@@ -213,23 +213,23 @@ void wl12xx_set_partition(struct wl12xx *wl,
            ((mem_start + mem_size) > reg_start)) {
                /* Guarantee that the memory partition doesn't overlap the
                 * registers partition */
-               wl12xx_debug(DEBUG_SPI, "End of partition[0] is "
+               wl1251_debug(DEBUG_SPI, "End of partition[0] is "
                             "overlapping partition[1].  Adjusted.");
                mem_size = reg_start - mem_start;
-               wl12xx_debug(DEBUG_SPI, "mem_start %08X mem_size %08X",
+               wl1251_debug(DEBUG_SPI, "mem_start %08X mem_size %08X",
                             mem_start, mem_size);
-               wl12xx_debug(DEBUG_SPI, "reg_start %08X reg_size %08X",
+               wl1251_debug(DEBUG_SPI, "reg_start %08X reg_size %08X",
                             reg_start, reg_size);
        } else if ((reg_start < mem_start) &&
                   ((reg_start + reg_size) > mem_start)) {
                /* Guarantee that the register partition doesn't overlap the
                 * memory partition */
-               wl12xx_debug(DEBUG_SPI, "End of partition[1] is"
+               wl1251_debug(DEBUG_SPI, "End of partition[1] is"
                             " overlapping partition[0].  Adjusted.");
                reg_size = mem_start - reg_start;
-               wl12xx_debug(DEBUG_SPI, "mem_start %08X mem_size %08X",
+               wl1251_debug(DEBUG_SPI, "mem_start %08X mem_size %08X",
                             mem_start, mem_size);
-               wl12xx_debug(DEBUG_SPI, "reg_start %08X reg_size %08X",
+               wl1251_debug(DEBUG_SPI, "reg_start %08X reg_size %08X",
                             reg_start, reg_size);
        }
 
@@ -244,36 +244,46 @@ void wl12xx_set_partition(struct wl12xx *wl,
        wl->virtual_mem_addr = 0;
        wl->virtual_reg_addr = mem_size;
 
-       t.tx_buf = tx_buf;
-       t.len = sizeof(tx_buf);
+       t.tx_buf = cmd;
+       t.len = cmd_len;
        spi_message_add_tail(&t, &m);
 
        spi_sync(wl->spi, &m);
+
+       kfree(cmd);
+
+       return 0;
 }
 
-void wl12xx_spi_read(struct wl12xx *wl, int addr, void *buf,
-                    size_t len)
+void wl1251_spi_read(struct wl1251 *wl, int addr, void *buf,
+                    size_t len, bool fixed)
 {
        struct spi_transfer t[3];
        struct spi_message m;
-       char busy_buf[TNETWIF_READ_OFFSET_BYTES];
-       u32 cmd;
+       u8 *busy_buf;
+       u32 *cmd;
+
+       cmd = &wl->buffer_cmd;
+       busy_buf = wl->buffer_busyword;
+
+       *cmd = 0;
+       *cmd |= WSPI_CMD_READ;
+       *cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH;
+       *cmd |= addr & WSPI_CMD_BYTE_ADDR;
 
-       cmd = 0;
-       cmd |= WSPI_CMD_READ;
-       cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH;
-       cmd |= addr & WSPI_CMD_BYTE_ADDR;
+       if (fixed)
+               *cmd |= WSPI_CMD_FIXED;
 
        spi_message_init(&m);
        memset(t, 0, sizeof(t));
 
-       t[0].tx_buf = &cmd;
+       t[0].tx_buf = cmd;
        t[0].len = 4;
        spi_message_add_tail(&t[0], &m);
 
        /* Busy and non busy words read */
        t[1].rx_buf = busy_buf;
-       t[1].len = TNETWIF_READ_OFFSET_BYTES;
+       t[1].len = WL1251_BUSY_WORD_LEN;
        spi_message_add_tail(&t[1], &m);
 
        t[2].rx_buf = buf;
@@ -284,27 +294,32 @@ void wl12xx_spi_read(struct wl12xx *wl, int addr, void *buf,
 
        /* FIXME: check busy words */
 
-       wl12xx_dump(DEBUG_SPI, "spi_read cmd -> ", &cmd, sizeof(cmd));
-       wl12xx_dump(DEBUG_SPI, "spi_read buf <- ", buf, len);
+       wl1251_dump(DEBUG_SPI, "spi_read cmd -> ", cmd, sizeof(*cmd));
+       wl1251_dump(DEBUG_SPI, "spi_read buf <- ", buf, len);
 }
 
-void wl12xx_spi_write(struct wl12xx *wl, int addr, void *buf,
-                     size_t len)
+void wl1251_spi_write(struct wl1251 *wl, int addr, void *buf,
+                     size_t len, bool fixed)
 {
        struct spi_transfer t[2];
        struct spi_message m;
-       u32 cmd;
+       u32 *cmd;
+
+       cmd = &wl->buffer_cmd;
 
-       cmd = 0;
-       cmd |= WSPI_CMD_WRITE;
-       cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH;
-       cmd |= addr & WSPI_CMD_BYTE_ADDR;
+       *cmd = 0;
+       *cmd |= WSPI_CMD_WRITE;
+       *cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH;
+       *cmd |= addr & WSPI_CMD_BYTE_ADDR;
+
+       if (fixed)
+               *cmd |= WSPI_CMD_FIXED;
 
        spi_message_init(&m);
        memset(t, 0, sizeof(t));
 
-       t[0].tx_buf = &cmd;
-       t[0].len = sizeof(cmd);
+       t[0].tx_buf = cmd;
+       t[0].len = sizeof(*cmd);
        spi_message_add_tail(&t[0], &m);
 
        t[1].tx_buf = buf;
@@ -313,46 +328,66 @@ void wl12xx_spi_write(struct wl12xx *wl, int addr, void *buf,
 
        spi_sync(wl->spi, &m);
 
-       wl12xx_dump(DEBUG_SPI, "spi_write cmd -> ", &cmd, sizeof(cmd));
-       wl12xx_dump(DEBUG_SPI, "spi_write buf -> ", buf, len);
+       wl1251_dump(DEBUG_SPI, "spi_write cmd -> ", cmd, sizeof(*cmd));
+       wl1251_dump(DEBUG_SPI, "spi_write buf -> ", buf, len);
 }
 
-void wl12xx_spi_mem_read(struct wl12xx *wl, int addr, void *buf,
+void wl1251_spi_mem_read(struct wl1251 *wl, int addr, void *buf,
                         size_t len)
 {
        int physical;
 
-       physical = wl12xx_translate_mem_addr(wl, addr);
+       physical = wl1251_translate_mem_addr(wl, addr);
 
-       wl12xx_spi_read(wl, physical, buf, len);
+       wl1251_spi_read(wl, physical, buf, len, false);
 }
 
-void wl12xx_spi_mem_write(struct wl12xx *wl, int addr, void *buf,
+void wl1251_spi_mem_write(struct wl1251 *wl, int addr, void *buf,
                          size_t len)
 {
        int physical;
 
-       physical = wl12xx_translate_mem_addr(wl, addr);
+       physical = wl1251_translate_mem_addr(wl, addr);
+
+       wl1251_spi_write(wl, physical, buf, len, false);
+}
+
+void wl1251_spi_reg_read(struct wl1251 *wl, int addr, void *buf, size_t len,
+                        bool fixed)
+{
+       int physical;
+
+       physical = wl1251_translate_reg_addr(wl, addr);
+
+       wl1251_spi_read(wl, physical, buf, len, fixed);
+}
+
+void wl1251_spi_reg_write(struct wl1251 *wl, int addr, void *buf, size_t len,
+                         bool fixed)
+{
+       int physical;
+
+       physical = wl1251_translate_reg_addr(wl, addr);
 
-       wl12xx_spi_write(wl, physical, buf, len);
+       wl1251_spi_write(wl, physical, buf, len, fixed);
 }
 
-u32 wl12xx_mem_read32(struct wl12xx *wl, int addr)
+u32 wl1251_mem_read32(struct wl1251 *wl, int addr)
 {
-       return wl12xx_read32(wl, wl12xx_translate_mem_addr(wl, addr));
+       return wl1251_read32(wl, wl1251_translate_mem_addr(wl, addr));
 }
 
-void wl12xx_mem_write32(struct wl12xx *wl, int addr, u32 val)
+void wl1251_mem_write32(struct wl1251 *wl, int addr, u32 val)
 {
-       wl12xx_write32(wl, wl12xx_translate_mem_addr(wl, addr), val);
+       wl1251_write32(wl, wl1251_translate_mem_addr(wl, addr), val);
 }
 
-u32 wl12xx_reg_read32(struct wl12xx *wl, int addr)
+u32 wl1251_reg_read32(struct wl1251 *wl, int addr)
 {
-       return wl12xx_read32(wl, wl12xx_translate_reg_addr(wl, addr));
+       return wl1251_read32(wl, wl1251_translate_reg_addr(wl, addr));
 }
 
-void wl12xx_reg_write32(struct wl12xx *wl, int addr, u32 val)
+void wl1251_reg_write32(struct wl1251 *wl, int addr, u32 val)
 {
-       wl12xx_write32(wl, wl12xx_translate_reg_addr(wl, addr), val);
+       wl1251_write32(wl, wl1251_translate_reg_addr(wl, addr), val);
 }
similarity index 61%
rename from drivers/net/wireless/wl12xx/spi.h
rename to drivers/net/wireless/wl12xx/wl1251_spi.h
index fd3227e..6e8daf4 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * This file is part of wl12xx
+ * This file is part of wl1251
  *
  * Copyright (c) 1998-2007 Texas Instruments Incorporated
  * Copyright (C) 2008 Nokia Corporation
  *
  */
 
-#ifndef __WL12XX_SPI_H__
-#define __WL12XX_SPI_H__
+#ifndef __WL1251_SPI_H__
+#define __WL1251_SPI_H__
 
-#include "cmd.h"
-#include "acx.h"
+#include "wl1251_cmd.h"
+#include "wl1251_acx.h"
 #include "reg.h"
 
 #define HW_ACCESS_MEMORY_MAX_RANGE             0x1FFC0
 
 #define WSPI_INIT_CMD_LEN           8
 
-#define TNETWIF_READ_OFFSET_BYTES  8
 #define HW_ACCESS_WSPI_FIXED_BUSY_LEN \
-               ((TNETWIF_READ_OFFSET_BYTES - 4) / sizeof(u32))
+               ((WL1251_BUSY_WORD_LEN - 4) / sizeof(u32))
 #define HW_ACCESS_WSPI_INIT_CMD_MASK  0
 
 
 /* Raw target IO, address is not translated */
-void wl12xx_spi_read(struct wl12xx *wl, int addr, void *buf, size_t len);
-void wl12xx_spi_write(struct wl12xx *wl, int addr, void *buf, size_t len);
+void wl1251_spi_write(struct wl1251 *wl, int addr, void *buf,
+                     size_t len, bool fixed);
+void wl1251_spi_read(struct wl1251 *wl, int addr, void *buf,
+                    size_t len, bool fixed);
 
 /* Memory target IO, address is tranlated to partition 0 */
-void wl12xx_spi_mem_read(struct wl12xx *wl, int addr, void *buf, size_t len);
-void wl12xx_spi_mem_write(struct wl12xx *wl, int addr, void *buf, size_t len);
-u32 wl12xx_mem_read32(struct wl12xx *wl, int addr);
-void wl12xx_mem_write32(struct wl12xx *wl, int addr, u32 val);
+void wl1251_spi_mem_read(struct wl1251 *wl, int addr, void *buf, size_t len);
+void wl1251_spi_mem_write(struct wl1251 *wl, int addr, void *buf, size_t len);
+u32 wl1251_mem_read32(struct wl1251 *wl, int addr);
+void wl1251_mem_write32(struct wl1251 *wl, int addr, u32 val);
 
 /* Registers IO */
-u32 wl12xx_reg_read32(struct wl12xx *wl, int addr);
-void wl12xx_reg_write32(struct wl12xx *wl, int addr, u32 val);
+void wl1251_spi_reg_read(struct wl1251 *wl, int addr, void *buf, size_t len,
+                        bool fixed);
+void wl1251_spi_reg_write(struct wl1251 *wl, int addr, void *buf, size_t len,
+                         bool fixed);
+u32 wl1251_reg_read32(struct wl1251 *wl, int addr);
+void wl1251_reg_write32(struct wl1251 *wl, int addr, u32 val);
 
 /* INIT and RESET words */
-void wl12xx_spi_reset(struct wl12xx *wl);
-void wl12xx_spi_init(struct wl12xx *wl);
-void wl12xx_set_partition(struct wl12xx *wl,
-                         u32 part_start, u32 part_size,
-                         u32 reg_start,  u32 reg_size);
+void wl1251_spi_reset(struct wl1251 *wl);
+void wl1251_spi_init(struct wl1251 *wl);
+int wl1251_set_partition(struct wl1251 *wl,
+                        u32 part_start, u32 part_size,
+                        u32 reg_start,  u32 reg_size);
 
-static inline u32 wl12xx_read32(struct wl12xx *wl, int addr)
+static inline u32 wl1251_read32(struct wl1251 *wl, int addr)
 {
-       u32 response;
+       wl1251_spi_read(wl, addr, &wl->buffer_32,
+                       sizeof(wl->buffer_32), false);
 
-       wl12xx_spi_read(wl, addr, &response, sizeof(u32));
-
-       return response;
+       return wl->buffer_32;
 }
 
-static inline void wl12xx_write32(struct wl12xx *wl, int addr, u32 val)
+static inline void wl1251_write32(struct wl1251 *wl, int addr, u32 val)
 {
-       wl12xx_spi_write(wl, addr, &val, sizeof(u32));
+       wl->buffer_32 = val;
+       wl1251_spi_write(wl, addr, &wl->buffer_32,
+                        sizeof(wl->buffer_32), false);
 }
 
-#endif /* __WL12XX_SPI_H__ */
+#endif /* __WL1251_SPI_H__ */
similarity index 79%
rename from drivers/net/wireless/wl12xx/tx.c
rename to drivers/net/wireless/wl12xx/wl1251_tx.c
index 62145e2..2652a22 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * This file is part of wl12xx
+ * This file is part of wl1251
  *
  * Copyright (c) 1998-2007 Texas Instruments Incorporated
  * Copyright (C) 2008 Nokia Corporation
 #include <linux/kernel.h>
 #include <linux/module.h>
 
-#include "wl12xx.h"
+#include "wl1251.h"
 #include "reg.h"
-#include "spi.h"
-#include "tx.h"
-#include "ps.h"
+#include "wl1251_spi.h"
+#include "wl1251_tx.h"
+#include "wl1251_ps.h"
 
-static bool wl12xx_tx_double_buffer_busy(struct wl12xx *wl, u32 data_out_count)
+static bool wl1251_tx_double_buffer_busy(struct wl1251 *wl, u32 data_out_count)
 {
        int used, data_in_count;
 
@@ -52,15 +52,15 @@ static bool wl12xx_tx_double_buffer_busy(struct wl12xx *wl, u32 data_out_count)
                return false;
 }
 
-static int wl12xx_tx_path_status(struct wl12xx *wl)
+static int wl1251_tx_path_status(struct wl1251 *wl)
 {
        u32 status, addr, data_out_count;
        bool busy;
 
        addr = wl->data_path->tx_control_addr;
-       status = wl12xx_mem_read32(wl, addr);
+       status = wl1251_mem_read32(wl, addr);
        data_out_count = status & TX_STATUS_DATA_OUT_COUNT_MASK;
-       busy = wl12xx_tx_double_buffer_busy(wl, data_out_count);
+       busy = wl1251_tx_double_buffer_busy(wl, data_out_count);
 
        if (busy)
                return -EBUSY;
@@ -68,7 +68,7 @@ static int wl12xx_tx_path_status(struct wl12xx *wl)
        return 0;
 }
 
-static int wl12xx_tx_id(struct wl12xx *wl, struct sk_buff *skb)
+static int wl1251_tx_id(struct wl1251 *wl, struct sk_buff *skb)
 {
        int i;
 
@@ -81,7 +81,7 @@ static int wl12xx_tx_id(struct wl12xx *wl, struct sk_buff *skb)
        return -EBUSY;
 }
 
-static void wl12xx_tx_control(struct tx_double_buffer_desc *tx_hdr,
+static void wl1251_tx_control(struct tx_double_buffer_desc *tx_hdr,
                              struct ieee80211_tx_info *control, u16 fc)
 {
        *(u16 *)&tx_hdr->control = 0;
@@ -109,7 +109,7 @@ static void wl12xx_tx_control(struct tx_double_buffer_desc *tx_hdr,
 #define MAX_MPDU_HEADER_AND_SECURITY  (MAX_MPDU_SECURITY_LENGTH + \
                                       WLAN_QOS_HDR_LEN)
 #define HW_BLOCK_SIZE                 252
-static void wl12xx_tx_frag_block_num(struct tx_double_buffer_desc *tx_hdr)
+static void wl1251_tx_frag_block_num(struct tx_double_buffer_desc *tx_hdr)
 {
        u16 payload_len, frag_threshold, mem_blocks;
        u16 num_mpdus, mem_blocks_per_frag;
@@ -142,7 +142,7 @@ static void wl12xx_tx_frag_block_num(struct tx_double_buffer_desc *tx_hdr)
        tx_hdr->num_mem_blocks = mem_blocks;
 }
 
-static int wl12xx_tx_fill_hdr(struct wl12xx *wl, struct sk_buff *skb,
+static int wl1251_tx_fill_hdr(struct wl1251 *wl, struct sk_buff *skb,
                              struct ieee80211_tx_info *control)
 {
        struct tx_double_buffer_desc *tx_hdr;
@@ -153,7 +153,7 @@ static int wl12xx_tx_fill_hdr(struct wl12xx *wl, struct sk_buff *skb,
        if (!skb)
                return -EINVAL;
 
-       id = wl12xx_tx_id(wl, skb);
+       id = wl1251_tx_id(wl, skb);
        if (id < 0)
                return id;
 
@@ -170,14 +170,14 @@ static int wl12xx_tx_fill_hdr(struct wl12xx *wl, struct sk_buff *skb,
        /* FIXME: how to get the correct queue id? */
        tx_hdr->xmit_queue = 0;
 
-       wl12xx_tx_control(tx_hdr, control, fc);
-       wl12xx_tx_frag_block_num(tx_hdr);
+       wl1251_tx_control(tx_hdr, control, fc);
+       wl1251_tx_frag_block_num(tx_hdr);
 
        return 0;
 }
 
 /* We copy the packet to the target */
-static int wl12xx_tx_send_packet(struct wl12xx *wl, struct sk_buff *skb,
+static int wl1251_tx_send_packet(struct wl1251 *wl, struct sk_buff *skb,
                                 struct ieee80211_tx_info *control)
 {
        struct tx_double_buffer_desc *tx_hdr;
@@ -196,12 +196,12 @@ static int wl12xx_tx_send_packet(struct wl12xx *wl, struct sk_buff *skb,
                u8 *pos;
 
                fc = *(u16 *)(skb->data + sizeof(*tx_hdr));
-               tx_hdr->length += WL12XX_TKIP_IV_SPACE;
+               tx_hdr->length += WL1251_TKIP_IV_SPACE;
 
                hdrlen = ieee80211_hdrlen(fc);
 
-               pos = skb_push(skb, WL12XX_TKIP_IV_SPACE);
-               memmove(pos, pos + WL12XX_TKIP_IV_SPACE,
+               pos = skb_push(skb, WL1251_TKIP_IV_SPACE);
+               memmove(pos, pos + WL1251_TKIP_IV_SPACE,
                        sizeof(*tx_hdr) + hdrlen);
        }
 
@@ -211,7 +211,7 @@ static int wl12xx_tx_send_packet(struct wl12xx *wl, struct sk_buff *skb,
        */
        if (unlikely((long)skb->data & 0x03)) {
                int offset = (4 - (long)skb->data) & 0x03;
-               wl12xx_debug(DEBUG_TX, "skb offset %d", offset);
+               wl1251_debug(DEBUG_TX, "skb offset %d", offset);
 
                /* check whether the current skb can be used */
                if (!skb_cloned(skb) && (skb_tailroom(skb) >= offset)) {
@@ -221,13 +221,13 @@ static int wl12xx_tx_send_packet(struct wl12xx *wl, struct sk_buff *skb,
                        skb_reserve(skb, offset);
                        memmove(skb->data, src, skb->len);
                } else {
-                       wl12xx_info("No handler, fixme!");
+                       wl1251_info("No handler, fixme!");
                        return -EINVAL;
                }
        }
 
        /* Our skb->data at this point includes the HW header */
-       len = WL12XX_TX_ALIGN(skb->len);
+       len = WL1251_TX_ALIGN(skb->len);
 
        if (wl->data_in_count & 0x1)
                addr = wl->data_path->tx_packet_ring_addr +
@@ -235,15 +235,15 @@ static int wl12xx_tx_send_packet(struct wl12xx *wl, struct sk_buff *skb,
        else
                addr = wl->data_path->tx_packet_ring_addr;
 
-       wl12xx_spi_mem_write(wl, addr, skb->data, len);
+       wl1251_spi_mem_write(wl, addr, skb->data, len);
 
-       wl12xx_debug(DEBUG_TX, "tx id %u skb 0x%p payload %u rate 0x%x",
+       wl1251_debug(DEBUG_TX, "tx id %u skb 0x%p payload %u rate 0x%x",
                     tx_hdr->id, skb, tx_hdr->length, tx_hdr->rate);
 
        return 0;
 }
 
-static void wl12xx_tx_trigger(struct wl12xx *wl)
+static void wl1251_tx_trigger(struct wl1251 *wl)
 {
        u32 data, addr;
 
@@ -255,7 +255,7 @@ static void wl12xx_tx_trigger(struct wl12xx *wl)
                data = INTR_TRIG_TX_PROC0;
        }
 
-       wl12xx_reg_write32(wl, addr, data);
+       wl1251_reg_write32(wl, addr, data);
 
        /* Bumping data in */
        wl->data_in_count = (wl->data_in_count + 1) &
@@ -263,7 +263,7 @@ static void wl12xx_tx_trigger(struct wl12xx *wl)
 }
 
 /* caller must hold wl->mutex */
-static int wl12xx_tx_frame(struct wl12xx *wl, struct sk_buff *skb)
+static int wl1251_tx_frame(struct wl1251 *wl, struct sk_buff *skb)
 {
        struct ieee80211_tx_info *info;
        int ret = 0;
@@ -274,51 +274,53 @@ static int wl12xx_tx_frame(struct wl12xx *wl, struct sk_buff *skb)
        if (info->control.hw_key) {
                idx = info->control.hw_key->hw_key_idx;
                if (unlikely(wl->default_key != idx)) {
-                       ret = wl12xx_acx_default_key(wl, idx);
+                       ret = wl1251_acx_default_key(wl, idx);
                        if (ret < 0)
                                return ret;
                }
        }
 
-       ret = wl12xx_tx_path_status(wl);
+       ret = wl1251_tx_path_status(wl);
        if (ret < 0)
                return ret;
 
-       ret = wl12xx_tx_fill_hdr(wl, skb, info);
+       ret = wl1251_tx_fill_hdr(wl, skb, info);
        if (ret < 0)
                return ret;
 
-       ret = wl12xx_tx_send_packet(wl, skb, info);
+       ret = wl1251_tx_send_packet(wl, skb, info);
        if (ret < 0)
                return ret;
 
-       wl12xx_tx_trigger(wl);
+       wl1251_tx_trigger(wl);
 
        return ret;
 }
 
-void wl12xx_tx_work(struct work_struct *work)
+void wl1251_tx_work(struct work_struct *work)
 {
-       struct wl12xx *wl = container_of(work, struct wl12xx, tx_work);
+       struct wl1251 *wl = container_of(work, struct wl1251, tx_work);
        struct sk_buff *skb;
        bool woken_up = false;
        int ret;
 
        mutex_lock(&wl->mutex);
 
-       if (unlikely(wl->state == WL12XX_STATE_OFF))
+       if (unlikely(wl->state == WL1251_STATE_OFF))
                goto out;
 
        while ((skb = skb_dequeue(&wl->tx_queue))) {
                if (!woken_up) {
-                       wl12xx_ps_elp_wakeup(wl);
+                       ret = wl1251_ps_elp_wakeup(wl);
+                       if (ret < 0)
+                               goto out;
                        woken_up = true;
                }
 
-               ret = wl12xx_tx_frame(wl, skb);
+               ret = wl1251_tx_frame(wl, skb);
                if (ret == -EBUSY) {
                        /* firmware buffer is full, stop queues */
-                       wl12xx_debug(DEBUG_TX, "tx_work: fw buffer full, "
+                       wl1251_debug(DEBUG_TX, "tx_work: fw buffer full, "
                                     "stop queues");
                        ieee80211_stop_queues(wl->hw);
                        wl->tx_queue_stopped = true;
@@ -332,12 +334,12 @@ void wl12xx_tx_work(struct work_struct *work)
 
 out:
        if (woken_up)
-               wl12xx_ps_elp_sleep(wl);
+               wl1251_ps_elp_sleep(wl);
 
        mutex_unlock(&wl->mutex);
 }
 
-static const char *wl12xx_tx_parse_status(u8 status)
+static const char *wl1251_tx_parse_status(u8 status)
 {
        /* 8 bit status field, one character per bit plus null */
        static char buf[9];
@@ -365,7 +367,7 @@ static const char *wl12xx_tx_parse_status(u8 status)
        return buf;
 }
 
-static void wl12xx_tx_packet_cb(struct wl12xx *wl,
+static void wl1251_tx_packet_cb(struct wl1251 *wl,
                                struct tx_result *result)
 {
        struct ieee80211_tx_info *info;
@@ -375,7 +377,7 @@ static void wl12xx_tx_packet_cb(struct wl12xx *wl,
 
        skb = wl->tx_frames[result->id];
        if (skb == NULL) {
-               wl12xx_error("SKB for packet %d is NULL", result->id);
+               wl1251_error("SKB for packet %d is NULL", result->id);
                return;
        }
 
@@ -396,14 +398,14 @@ static void wl12xx_tx_packet_cb(struct wl12xx *wl,
        if (info->control.hw_key &&
            info->control.hw_key->alg == ALG_TKIP) {
                hdrlen = ieee80211_get_hdrlen_from_skb(skb);
-               memmove(frame + WL12XX_TKIP_IV_SPACE, frame, hdrlen);
-               skb_pull(skb, WL12XX_TKIP_IV_SPACE);
+               memmove(frame + WL1251_TKIP_IV_SPACE, frame, hdrlen);
+               skb_pull(skb, WL1251_TKIP_IV_SPACE);
        }
 
-       wl12xx_debug(DEBUG_TX, "tx status id %u skb 0x%p failures %u rate 0x%x"
+       wl1251_debug(DEBUG_TX, "tx status id %u skb 0x%p failures %u rate 0x%x"
                     " status 0x%x (%s)",
                     result->id, skb, result->ack_failures, result->rate,
-                    result->status, wl12xx_tx_parse_status(result->status));
+                    result->status, wl1251_tx_parse_status(result->status));
 
 
        ieee80211_tx_status(wl->hw, skb);
@@ -411,7 +413,7 @@ static void wl12xx_tx_packet_cb(struct wl12xx *wl,
        wl->tx_frames[result->id] = NULL;
 
        if (wl->tx_queue_stopped) {
-               wl12xx_debug(DEBUG_TX, "cb: queue was stopped");
+               wl1251_debug(DEBUG_TX, "cb: queue was stopped");
 
                skb = skb_dequeue(&wl->tx_queue);
 
@@ -420,10 +422,10 @@ static void wl12xx_tx_packet_cb(struct wl12xx *wl,
                   queue empty */
 
                if (skb) {
-                       ret = wl12xx_tx_frame(wl, skb);
+                       ret = wl1251_tx_frame(wl, skb);
                        if (ret == -EBUSY) {
                                /* firmware buffer is still full */
-                               wl12xx_debug(DEBUG_TX, "cb: fw buffer "
+                               wl1251_debug(DEBUG_TX, "cb: fw buffer "
                                             "still full");
                                skb_queue_head(&wl->tx_queue, skb);
                                return;
@@ -433,23 +435,23 @@ static void wl12xx_tx_packet_cb(struct wl12xx *wl,
                        }
                }
 
-               wl12xx_debug(DEBUG_TX, "cb: waking queues");
+               wl1251_debug(DEBUG_TX, "cb: waking queues");
                ieee80211_wake_queues(wl->hw);
                wl->tx_queue_stopped = false;
        }
 }
 
 /* Called upon reception of a TX complete interrupt */
-void wl12xx_tx_complete(struct wl12xx *wl)
+void wl1251_tx_complete(struct wl1251 *wl)
 {
        int i, result_index, num_complete = 0;
        struct tx_result result[FW_TX_CMPLT_BLOCK_SIZE], *result_ptr;
 
-       if (unlikely(wl->state != WL12XX_STATE_ON))
+       if (unlikely(wl->state != WL1251_STATE_ON))
                return;
 
        /* First we read the result */
-       wl12xx_spi_mem_read(wl, wl->data_path->tx_complete_addr,
+       wl1251_spi_mem_read(wl, wl->data_path->tx_complete_addr,
                            result, sizeof(result));
 
        result_index = wl->next_tx_complete;
@@ -459,7 +461,7 @@ void wl12xx_tx_complete(struct wl12xx *wl)
 
                if (result_ptr->done_1 == 1 &&
                    result_ptr->done_2 == 1) {
-                       wl12xx_tx_packet_cb(wl, result_ptr);
+                       wl1251_tx_packet_cb(wl, result_ptr);
 
                        result_ptr->done_1 = 0;
                        result_ptr->done_2 = 0;
@@ -480,7 +482,7 @@ void wl12xx_tx_complete(struct wl12xx *wl)
                 */
                if (result_index > wl->next_tx_complete) {
                        /* Only 1 write is needed */
-                       wl12xx_spi_mem_write(wl,
+                       wl1251_spi_mem_write(wl,
                                             wl->data_path->tx_complete_addr +
                                             (wl->next_tx_complete *
                                              sizeof(struct tx_result)),
@@ -491,7 +493,7 @@ void wl12xx_tx_complete(struct wl12xx *wl)
 
                } else if (result_index < wl->next_tx_complete) {
                        /* 2 writes are needed */
-                       wl12xx_spi_mem_write(wl,
+                       wl1251_spi_mem_write(wl,
                                             wl->data_path->tx_complete_addr +
                                             (wl->next_tx_complete *
                                              sizeof(struct tx_result)),
@@ -500,7 +502,7 @@ void wl12xx_tx_complete(struct wl12xx *wl)
                                              wl->next_tx_complete) *
                                             sizeof(struct tx_result));
 
-                       wl12xx_spi_mem_write(wl,
+                       wl1251_spi_mem_write(wl,
                                             wl->data_path->tx_complete_addr,
                                             result,
                                             (num_complete -
@@ -510,7 +512,7 @@ void wl12xx_tx_complete(struct wl12xx *wl)
 
                } else {
                        /* We have to write the whole array */
-                       wl12xx_spi_mem_write(wl,
+                       wl1251_spi_mem_write(wl,
                                             wl->data_path->tx_complete_addr,
                                             result,
                                             FW_TX_CMPLT_BLOCK_SIZE *
@@ -523,7 +525,7 @@ void wl12xx_tx_complete(struct wl12xx *wl)
 }
 
 /* caller must hold wl->mutex */
-void wl12xx_tx_flush(struct wl12xx *wl)
+void wl1251_tx_flush(struct wl1251 *wl)
 {
        int i;
        struct sk_buff *skb;
@@ -535,7 +537,7 @@ void wl12xx_tx_flush(struct wl12xx *wl)
        while ((skb = skb_dequeue(&wl->tx_queue))) {
                info = IEEE80211_SKB_CB(skb);
 
-               wl12xx_debug(DEBUG_TX, "flushing skb 0x%p", skb);
+               wl1251_debug(DEBUG_TX, "flushing skb 0x%p", skb);
 
                if (!(info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS))
                                continue;
similarity index 93%
rename from drivers/net/wireless/wl12xx/tx.h
rename to drivers/net/wireless/wl12xx/wl1251_tx.h
index dc82691..7c1c166 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * This file is part of wl12xx
+ * This file is part of wl1251
  *
  * Copyright (c) 1998-2007 Texas Instruments Incorporated
  * Copyright (C) 2008 Nokia Corporation
@@ -22,8 +22,8 @@
  *
  */
 
-#ifndef __WL12XX_TX_H__
-#define __WL12XX_TX_H__
+#ifndef __WL1251_TX_H__
+#define __WL1251_TX_H__
 
 #include <linux/bitops.h>
 
 
 #define TX_COMPLETE_REQUIRED_BIT       0x80
 #define TX_STATUS_DATA_OUT_COUNT_MASK   0xf
-#define WL12XX_TX_ALIGN_TO 4
-#define WL12XX_TX_ALIGN(len) (((len) + WL12XX_TX_ALIGN_TO - 1) & \
-                            ~(WL12XX_TX_ALIGN_TO - 1))
-#define WL12XX_TKIP_IV_SPACE 4
+
+#define WL1251_TX_ALIGN_TO 4
+#define WL1251_TX_ALIGN(len) (((len) + WL1251_TX_ALIGN_TO - 1) & \
+                            ~(WL1251_TX_ALIGN_TO - 1))
+#define WL1251_TKIP_IV_SPACE 4
 
 struct tx_control {
        /* Rate Policy (class) index */
@@ -208,8 +209,8 @@ struct tx_result {
        u8 done_2;
 } __attribute__ ((packed));
 
-void wl12xx_tx_work(struct work_struct *work);
-void wl12xx_tx_complete(struct wl12xx *wl);
-void wl12xx_tx_flush(struct wl12xx *wl);
+void wl1251_tx_work(struct work_struct *work);
+void wl1251_tx_complete(struct wl1251 *wl);
+void wl1251_tx_flush(struct wl1251 *wl);
 
 #endif
diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h
deleted file mode 100644 (file)
index 4864143..0000000
+++ /dev/null
@@ -1,409 +0,0 @@
-/*
- * This file is part of wl12xx
- *
- * Copyright (c) 1998-2007 Texas Instruments Incorporated
- * Copyright (C) 2008-2009 Nokia Corporation
- *
- * Contact: Kalle Valo <kalle.valo@nokia.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 St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-
-#ifndef __WL12XX_H__
-#define __WL12XX_H__
-
-#include <linux/mutex.h>
-#include <linux/list.h>
-#include <linux/bitops.h>
-#include <net/mac80211.h>
-
-#define DRIVER_NAME "wl12xx"
-#define DRIVER_PREFIX DRIVER_NAME ": "
-
-enum {
-       DEBUG_NONE      = 0,
-       DEBUG_IRQ       = BIT(0),
-       DEBUG_SPI       = BIT(1),
-       DEBUG_BOOT      = BIT(2),
-       DEBUG_MAILBOX   = BIT(3),
-       DEBUG_NETLINK   = BIT(4),
-       DEBUG_EVENT     = BIT(5),
-       DEBUG_TX        = BIT(6),
-       DEBUG_RX        = BIT(7),
-       DEBUG_SCAN      = BIT(8),
-       DEBUG_CRYPT     = BIT(9),
-       DEBUG_PSM       = BIT(10),
-       DEBUG_MAC80211  = BIT(11),
-       DEBUG_CMD       = BIT(12),
-       DEBUG_ACX       = BIT(13),
-       DEBUG_ALL       = ~0,
-};
-
-#define DEBUG_LEVEL (DEBUG_NONE)
-
-#define DEBUG_DUMP_LIMIT 1024
-
-#define wl12xx_error(fmt, arg...) \
-       printk(KERN_ERR DRIVER_PREFIX "ERROR " fmt "\n", ##arg)
-
-#define wl12xx_warning(fmt, arg...) \
-       printk(KERN_WARNING DRIVER_PREFIX "WARNING " fmt "\n", ##arg)
-
-#define wl12xx_notice(fmt, arg...) \
-       printk(KERN_INFO DRIVER_PREFIX fmt "\n", ##arg)
-
-#define wl12xx_info(fmt, arg...) \
-       printk(KERN_DEBUG DRIVER_PREFIX fmt "\n", ##arg)
-
-#define wl12xx_debug(level, fmt, arg...) \
-       do { \
-               if (level & DEBUG_LEVEL) \
-                       printk(KERN_DEBUG DRIVER_PREFIX fmt "\n", ##arg); \
-       } while (0)
-
-#define wl12xx_dump(level, prefix, buf, len)   \
-       do { \
-               if (level & DEBUG_LEVEL) \
-                       print_hex_dump(KERN_DEBUG, DRIVER_PREFIX prefix, \
-                                      DUMP_PREFIX_OFFSET, 16, 1,       \
-                                      buf,                             \
-                                      min_t(size_t, len, DEBUG_DUMP_LIMIT), \
-                                      0);                              \
-       } while (0)
-
-#define wl12xx_dump_ascii(level, prefix, buf, len)     \
-       do { \
-               if (level & DEBUG_LEVEL) \
-                       print_hex_dump(KERN_DEBUG, DRIVER_PREFIX prefix, \
-                                      DUMP_PREFIX_OFFSET, 16, 1,       \
-                                      buf,                             \
-                                      min_t(size_t, len, DEBUG_DUMP_LIMIT), \
-                                      true);                           \
-       } while (0)
-
-#define WL12XX_DEFAULT_RX_CONFIG (CFG_UNI_FILTER_EN |  \
-                                 CFG_BSSID_FILTER_EN)
-
-#define WL12XX_DEFAULT_RX_FILTER (CFG_RX_PRSP_EN |  \
-                                 CFG_RX_MGMT_EN |  \
-                                 CFG_RX_DATA_EN |  \
-                                 CFG_RX_CTL_EN |   \
-                                 CFG_RX_BCN_EN |   \
-                                 CFG_RX_AUTH_EN |  \
-                                 CFG_RX_ASSOC_EN)
-
-
-struct boot_attr {
-       u32 radio_type;
-       u8 mac_clock;
-       u8 arm_clock;
-       int firmware_debug;
-       u32 minor;
-       u32 major;
-       u32 bugfix;
-};
-
-enum wl12xx_state {
-       WL12XX_STATE_OFF,
-       WL12XX_STATE_ON,
-       WL12XX_STATE_PLT,
-};
-
-enum wl12xx_partition_type {
-       PART_DOWN,
-       PART_WORK,
-       PART_DRPW,
-
-       PART_TABLE_LEN
-};
-
-struct wl12xx_partition {
-       u32 size;
-       u32 start;
-};
-
-struct wl12xx_partition_set {
-       struct wl12xx_partition mem;
-       struct wl12xx_partition reg;
-};
-
-struct wl12xx;
-
-/* FIXME: I'm not sure about this structure name */
-struct wl12xx_chip {
-       u32 id;
-
-       const char *fw_filename;
-       const char *nvs_filename;
-
-       char fw_ver[21];
-
-       unsigned int power_on_sleep;
-       int intr_cmd_complete;
-       int intr_init_complete;
-
-       int (*op_upload_fw)(struct wl12xx *wl);
-       int (*op_upload_nvs)(struct wl12xx *wl);
-       int (*op_boot)(struct wl12xx *wl);
-       void (*op_set_ecpu_ctrl)(struct wl12xx *wl, u32 flag);
-       void (*op_target_enable_interrupts)(struct wl12xx *wl);
-       int (*op_hw_init)(struct wl12xx *wl);
-       int (*op_plt_init)(struct wl12xx *wl);
-
-       struct wl12xx_partition_set *p_table;
-       enum wl12xx_acx_int_reg *acx_reg_table;
-};
-
-struct wl12xx_stats {
-       struct acx_statistics *fw_stats;
-       unsigned long fw_stats_update;
-
-       unsigned int retry_count;
-       unsigned int excessive_retries;
-};
-
-struct wl12xx_debugfs {
-       struct dentry *rootdir;
-       struct dentry *fw_statistics;
-
-       struct dentry *tx_internal_desc_overflow;
-
-       struct dentry *rx_out_of_mem;
-       struct dentry *rx_hdr_overflow;
-       struct dentry *rx_hw_stuck;
-       struct dentry *rx_dropped;
-       struct dentry *rx_fcs_err;
-       struct dentry *rx_xfr_hint_trig;
-       struct dentry *rx_path_reset;
-       struct dentry *rx_reset_counter;
-
-       struct dentry *dma_rx_requested;
-       struct dentry *dma_rx_errors;
-       struct dentry *dma_tx_requested;
-       struct dentry *dma_tx_errors;
-
-       struct dentry *isr_cmd_cmplt;
-       struct dentry *isr_fiqs;
-       struct dentry *isr_rx_headers;
-       struct dentry *isr_rx_mem_overflow;
-       struct dentry *isr_rx_rdys;
-       struct dentry *isr_irqs;
-       struct dentry *isr_tx_procs;
-       struct dentry *isr_decrypt_done;
-       struct dentry *isr_dma0_done;
-       struct dentry *isr_dma1_done;
-       struct dentry *isr_tx_exch_complete;
-       struct dentry *isr_commands;
-       struct dentry *isr_rx_procs;
-       struct dentry *isr_hw_pm_mode_changes;
-       struct dentry *isr_host_acknowledges;
-       struct dentry *isr_pci_pm;
-       struct dentry *isr_wakeups;
-       struct dentry *isr_low_rssi;
-
-       struct dentry *wep_addr_key_count;
-       struct dentry *wep_default_key_count;
-       /* skipping wep.reserved */
-       struct dentry *wep_key_not_found;
-       struct dentry *wep_decrypt_fail;
-       struct dentry *wep_packets;
-       struct dentry *wep_interrupt;
-
-       struct dentry *pwr_ps_enter;
-       struct dentry *pwr_elp_enter;
-       struct dentry *pwr_missing_bcns;
-       struct dentry *pwr_wake_on_host;
-       struct dentry *pwr_wake_on_timer_exp;
-       struct dentry *pwr_tx_with_ps;
-       struct dentry *pwr_tx_without_ps;
-       struct dentry *pwr_rcvd_beacons;
-       struct dentry *pwr_power_save_off;
-       struct dentry *pwr_enable_ps;
-       struct dentry *pwr_disable_ps;
-       struct dentry *pwr_fix_tsf_ps;
-       /* skipping cont_miss_bcns_spread for now */
-       struct dentry *pwr_rcvd_awake_beacons;
-
-       struct dentry *mic_rx_pkts;
-       struct dentry *mic_calc_failure;
-
-       struct dentry *aes_encrypt_fail;
-       struct dentry *aes_decrypt_fail;
-       struct dentry *aes_encrypt_packets;
-       struct dentry *aes_decrypt_packets;
-       struct dentry *aes_encrypt_interrupt;
-       struct dentry *aes_decrypt_interrupt;
-
-       struct dentry *event_heart_beat;
-       struct dentry *event_calibration;
-       struct dentry *event_rx_mismatch;
-       struct dentry *event_rx_mem_empty;
-       struct dentry *event_rx_pool;
-       struct dentry *event_oom_late;
-       struct dentry *event_phy_transmit_error;
-       struct dentry *event_tx_stuck;
-
-       struct dentry *ps_pspoll_timeouts;
-       struct dentry *ps_upsd_timeouts;
-       struct dentry *ps_upsd_max_sptime;
-       struct dentry *ps_upsd_max_apturn;
-       struct dentry *ps_pspoll_max_apturn;
-       struct dentry *ps_pspoll_utilization;
-       struct dentry *ps_upsd_utilization;
-
-       struct dentry *rxpipe_rx_prep_beacon_drop;
-       struct dentry *rxpipe_descr_host_int_trig_rx_data;
-       struct dentry *rxpipe_beacon_buffer_thres_host_int_trig_rx_data;
-       struct dentry *rxpipe_missed_beacon_host_int_trig_rx_data;
-       struct dentry *rxpipe_tx_xfr_host_int_trig_rx_data;
-
-       struct dentry *tx_queue_len;
-
-       struct dentry *retry_count;
-       struct dentry *excessive_retries;
-};
-
-struct wl12xx {
-       struct ieee80211_hw *hw;
-       bool mac80211_registered;
-
-       struct spi_device *spi;
-
-       void (*set_power)(bool enable);
-       int irq;
-
-       enum wl12xx_state state;
-       struct mutex mutex;
-
-       int physical_mem_addr;
-       int physical_reg_addr;
-       int virtual_mem_addr;
-       int virtual_reg_addr;
-
-       struct wl12xx_chip chip;
-
-       int cmd_box_addr;
-       int event_box_addr;
-       struct boot_attr boot_attr;
-
-       u8 *fw;
-       size_t fw_len;
-       u8 *nvs;
-       size_t nvs_len;
-
-       u8 bssid[ETH_ALEN];
-       u8 mac_addr[ETH_ALEN];
-       u8 bss_type;
-       u8 listen_int;
-       int channel;
-
-       void *target_mem_map;
-       struct acx_data_path_params_resp *data_path;
-
-       /* Number of TX packets transferred to the FW, modulo 16 */
-       u32 data_in_count;
-
-       /* Frames scheduled for transmission, not handled yet */
-       struct sk_buff_head tx_queue;
-       bool tx_queue_stopped;
-
-       struct work_struct tx_work;
-       struct work_struct filter_work;
-
-       /* Pending TX frames */
-       struct sk_buff *tx_frames[16];
-
-       /*
-        * Index pointing to the next TX complete entry
-        * in the cyclic XT complete array we get from
-        * the FW.
-        */
-       u32 next_tx_complete;
-
-       /* FW Rx counter */
-       u32 rx_counter;
-
-       /* Rx frames handled */
-       u32 rx_handled;
-
-       /* Current double buffer */
-       u32 rx_current_buffer;
-       u32 rx_last_id;
-
-       /* The target interrupt mask */
-       u32 intr_mask;
-       struct work_struct irq_work;
-
-       /* The mbox event mask */
-       u32 event_mask;
-
-       /* Mailbox pointers */
-       u32 mbox_ptr[2];
-
-       /* Are we currently scanning */
-       bool scanning;
-
-       /* Our association ID */
-       u16 aid;
-
-       /* Default key (for WEP) */
-       u32 default_key;
-
-       unsigned int tx_mgmt_frm_rate;
-       unsigned int tx_mgmt_frm_mod;
-
-       unsigned int rx_config;
-       unsigned int rx_filter;
-
-       /* is firmware in elp mode */
-       bool elp;
-
-       /* we can be in psm, but not in elp, we have to differentiate */
-       bool psm;
-
-       /* PSM mode requested */
-       bool psm_requested;
-
-       /* in dBm */
-       int power_level;
-
-       struct wl12xx_stats stats;
-       struct wl12xx_debugfs debugfs;
-};
-
-int wl12xx_plt_start(struct wl12xx *wl);
-int wl12xx_plt_stop(struct wl12xx *wl);
-
-#define DEFAULT_HW_GEN_MODULATION_TYPE    CCK_LONG /* Long Preamble */
-#define DEFAULT_HW_GEN_TX_RATE          RATE_2MBPS
-#define JOIN_TIMEOUT 5000 /* 5000 milliseconds to join */
-
-#define WL12XX_DEFAULT_POWER_LEVEL 20
-
-#define WL12XX_TX_QUEUE_MAX_LENGTH 20
-
-/* Different chips need different sleep times after power on.  WL1271 needs
- * 200ms, WL1251 needs only 10ms.  By default we use 200ms, but as soon as we
- * know the chip ID, we change the sleep value in the wl12xx chip structure,
- * so in subsequent power ons, we don't waste more time then needed.  */
-#define WL12XX_DEFAULT_POWER_ON_SLEEP 200
-
-#define CHIP_ID_1251_PG10                 (0x7010101)
-#define CHIP_ID_1251_PG11                 (0x7020101)
-#define CHIP_ID_1251_PG12                 (0x7030101)
-#define CHIP_ID_1271_PG10                 (0x4030101)
-
-#endif
index e3e96bb..a83a562 100644 (file)
@@ -1348,7 +1348,6 @@ static int wl3501_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
        if (rc) {
                ++dev->stats.tx_dropped;
                netif_stop_queue(dev);
-               rc = NETDEV_TX_OK;
        } else {
                ++dev->stats.tx_packets;
                dev->stats.tx_bytes += skb->len;
@@ -1358,7 +1357,7 @@ static int wl3501_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
                        netif_stop_queue(dev);
        }
        spin_unlock_irqrestore(&this->lock, flags);
-       return rc;
+       return NETDEV_TX_OK;
 }
 
 static int wl3501_open(struct net_device *dev)
index 4430b8d..dae1bfb 100644 (file)
@@ -789,7 +789,7 @@ static int zd1201_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
        if (!zd->mac_enabled || zd->monitor) {
                dev->stats.tx_dropped++;
                kfree_skb(skb);
-               return 0;
+               return NETDEV_TX_OK;
        }
        netif_stop_queue(dev);
 
@@ -826,7 +826,7 @@ static int zd1201_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
        }
        kfree_skb(skb);
 
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 static void zd1201_tx_timeout(struct net_device *dev)
index 40b07b9..9600b72 100644 (file)
@@ -711,7 +711,8 @@ int zd_mac_rx(struct ieee80211_hw *hw, const u8 *buffer, unsigned int length)
 
        memcpy(skb_put(skb, length), buffer, length);
 
-       ieee80211_rx_irqsafe(hw, skb, &stats);
+       memcpy(IEEE80211_SKB_RXCB(skb), &stats, sizeof(stats));
+       ieee80211_rx_irqsafe(hw, skb);
        return 0;
 }
 
index 0e6e446..07d7ab6 100644 (file)
 
 static struct usb_device_id usb_ids[] = {
        /* ZD1211 */
+       { USB_DEVICE(0x0105, 0x145f), .driver_info = DEVICE_ZD1211 },
+       { USB_DEVICE(0x0586, 0x3401), .driver_info = DEVICE_ZD1211 },
+       { USB_DEVICE(0x0586, 0x3402), .driver_info = DEVICE_ZD1211 },
+       { USB_DEVICE(0x0586, 0x3407), .driver_info = DEVICE_ZD1211 },
+       { USB_DEVICE(0x0586, 0x3409), .driver_info = DEVICE_ZD1211 },
+       { USB_DEVICE(0x079b, 0x004a), .driver_info = DEVICE_ZD1211 },
+       { USB_DEVICE(0x07b8, 0x6001), .driver_info = DEVICE_ZD1211 },
        { USB_DEVICE(0x0ace, 0x1211), .driver_info = DEVICE_ZD1211 },
        { USB_DEVICE(0x0ace, 0xa211), .driver_info = DEVICE_ZD1211 },
-       { USB_DEVICE(0x126f, 0xa006), .driver_info = DEVICE_ZD1211 },
-       { USB_DEVICE(0x6891, 0xa727), .driver_info = DEVICE_ZD1211 },
+       { USB_DEVICE(0x0b05, 0x170c), .driver_info = DEVICE_ZD1211 },
+       { USB_DEVICE(0x0b3b, 0x1630), .driver_info = DEVICE_ZD1211 },
+       { USB_DEVICE(0x0b3b, 0x5630), .driver_info = DEVICE_ZD1211 },
        { USB_DEVICE(0x0df6, 0x9071), .driver_info = DEVICE_ZD1211 },
        { USB_DEVICE(0x0df6, 0x9075), .driver_info = DEVICE_ZD1211 },
-       { USB_DEVICE(0x157e, 0x300b), .driver_info = DEVICE_ZD1211 },
-       { USB_DEVICE(0x079b, 0x004a), .driver_info = DEVICE_ZD1211 },
-       { USB_DEVICE(0x1740, 0x2000), .driver_info = DEVICE_ZD1211 },
-       { USB_DEVICE(0x157e, 0x3204), .driver_info = DEVICE_ZD1211 },
-       { USB_DEVICE(0x0586, 0x3402), .driver_info = DEVICE_ZD1211 },
-       { USB_DEVICE(0x0b3b, 0x5630), .driver_info = DEVICE_ZD1211 },
-       { USB_DEVICE(0x0b05, 0x170c), .driver_info = DEVICE_ZD1211 },
+       { USB_DEVICE(0x126f, 0xa006), .driver_info = DEVICE_ZD1211 },
+       { USB_DEVICE(0x129b, 0x1666), .driver_info = DEVICE_ZD1211 },
+       { USB_DEVICE(0x13b1, 0x001e), .driver_info = DEVICE_ZD1211 },
        { USB_DEVICE(0x1435, 0x0711), .driver_info = DEVICE_ZD1211 },
-       { USB_DEVICE(0x0586, 0x3409), .driver_info = DEVICE_ZD1211 },
-       { USB_DEVICE(0x0b3b, 0x1630), .driver_info = DEVICE_ZD1211 },
-       { USB_DEVICE(0x0586, 0x3401), .driver_info = DEVICE_ZD1211 },
        { USB_DEVICE(0x14ea, 0xab13), .driver_info = DEVICE_ZD1211 },
-       { USB_DEVICE(0x13b1, 0x001e), .driver_info = DEVICE_ZD1211 },
-       { USB_DEVICE(0x0586, 0x3407), .driver_info = DEVICE_ZD1211 },
-       { USB_DEVICE(0x129b, 0x1666), .driver_info = DEVICE_ZD1211 },
        { USB_DEVICE(0x157e, 0x300a), .driver_info = DEVICE_ZD1211 },
-       { USB_DEVICE(0x0105, 0x145f), .driver_info = DEVICE_ZD1211 },
+       { USB_DEVICE(0x157e, 0x300b), .driver_info = DEVICE_ZD1211 },
+       { USB_DEVICE(0x157e, 0x3204), .driver_info = DEVICE_ZD1211 },
+       { USB_DEVICE(0x1740, 0x2000), .driver_info = DEVICE_ZD1211 },
+       { USB_DEVICE(0x6891, 0xa727), .driver_info = DEVICE_ZD1211 },
        /* ZD1211B */
+       { USB_DEVICE(0x0053, 0x5301), .driver_info = DEVICE_ZD1211B },
+       { USB_DEVICE(0x0411, 0x00da), .driver_info = DEVICE_ZD1211B },
+       { USB_DEVICE(0x0471, 0x1236), .driver_info = DEVICE_ZD1211B },
+       { USB_DEVICE(0x0471, 0x1237), .driver_info = DEVICE_ZD1211B },
+       { USB_DEVICE(0x050d, 0x705c), .driver_info = DEVICE_ZD1211B },
        { USB_DEVICE(0x054c, 0x0257), .driver_info = DEVICE_ZD1211B },
-       { USB_DEVICE(0x0ace, 0x1215), .driver_info = DEVICE_ZD1211B },
-       { USB_DEVICE(0x0ace, 0xb215), .driver_info = DEVICE_ZD1211B },
-       { USB_DEVICE(0x157e, 0x300d), .driver_info = DEVICE_ZD1211B },
+       { USB_DEVICE(0x0586, 0x340a), .driver_info = DEVICE_ZD1211B },
+       { USB_DEVICE(0x0586, 0x340f), .driver_info = DEVICE_ZD1211B },
+       { USB_DEVICE(0x0586, 0x3410), .driver_info = DEVICE_ZD1211B },
+       { USB_DEVICE(0x0586, 0x3412), .driver_info = DEVICE_ZD1211B },
+       { USB_DEVICE(0x0586, 0x3413), .driver_info = DEVICE_ZD1211B },
        { USB_DEVICE(0x079b, 0x0062), .driver_info = DEVICE_ZD1211B },
-       { USB_DEVICE(0x1582, 0x6003), .driver_info = DEVICE_ZD1211B },
-       { USB_DEVICE(0x050d, 0x705c), .driver_info = DEVICE_ZD1211B },
+       { USB_DEVICE(0x07b8, 0x6001), .driver_info = DEVICE_ZD1211B },
+       { USB_DEVICE(0x07fa, 0x1196), .driver_info = DEVICE_ZD1211B },
+       { USB_DEVICE(0x083a, 0x4505), .driver_info = DEVICE_ZD1211B },
        { USB_DEVICE(0x083a, 0xe503), .driver_info = DEVICE_ZD1211B },
        { USB_DEVICE(0x083a, 0xe506), .driver_info = DEVICE_ZD1211B },
-       { USB_DEVICE(0x083a, 0x4505), .driver_info = DEVICE_ZD1211B },
-       { USB_DEVICE(0x0471, 0x1236), .driver_info = DEVICE_ZD1211B },
-       { USB_DEVICE(0x13b1, 0x0024), .driver_info = DEVICE_ZD1211B },
-       { USB_DEVICE(0x0586, 0x340f), .driver_info = DEVICE_ZD1211B },
+       { USB_DEVICE(0x0ace, 0x1215), .driver_info = DEVICE_ZD1211B },
+       { USB_DEVICE(0x0ace, 0xb215), .driver_info = DEVICE_ZD1211B },
        { USB_DEVICE(0x0b05, 0x171b), .driver_info = DEVICE_ZD1211B },
-       { USB_DEVICE(0x0586, 0x3410), .driver_info = DEVICE_ZD1211B },
        { USB_DEVICE(0x0baf, 0x0121), .driver_info = DEVICE_ZD1211B },
-       { USB_DEVICE(0x0586, 0x3412), .driver_info = DEVICE_ZD1211B },
-       { USB_DEVICE(0x0586, 0x3413), .driver_info = DEVICE_ZD1211B },
-       { USB_DEVICE(0x0053, 0x5301), .driver_info = DEVICE_ZD1211B },
-       { USB_DEVICE(0x0411, 0x00da), .driver_info = DEVICE_ZD1211B },
-       { USB_DEVICE(0x2019, 0x5303), .driver_info = DEVICE_ZD1211B },
-       { USB_DEVICE(0x129b, 0x1667), .driver_info = DEVICE_ZD1211B },
        { USB_DEVICE(0x0cde, 0x001a), .driver_info = DEVICE_ZD1211B },
-       { USB_DEVICE(0x0586, 0x340a), .driver_info = DEVICE_ZD1211B },
-       { USB_DEVICE(0x0471, 0x1237), .driver_info = DEVICE_ZD1211B },
-       { USB_DEVICE(0x07fa, 0x1196), .driver_info = DEVICE_ZD1211B },
        { USB_DEVICE(0x0df6, 0x0036), .driver_info = DEVICE_ZD1211B },
-       { USB_DEVICE(0x07b8, 0x6001), .driver_info = DEVICE_ZD1211B },
+       { USB_DEVICE(0x129b, 0x1667), .driver_info = DEVICE_ZD1211B },
+       { USB_DEVICE(0x13b1, 0x0024), .driver_info = DEVICE_ZD1211B },
+       { USB_DEVICE(0x157e, 0x300d), .driver_info = DEVICE_ZD1211B },
+       { USB_DEVICE(0x1582, 0x6003), .driver_info = DEVICE_ZD1211B },
+       { USB_DEVICE(0x2019, 0x5303), .driver_info = DEVICE_ZD1211B },
        /* "Driverless" devices that need ejecting */
        { USB_DEVICE(0x0ace, 0x2011), .driver_info = DEVICE_INSTALLER },
        { USB_DEVICE(0x0ace, 0x20ff), .driver_info = DEVICE_INSTALLER },
index 8d88dae..3700c49 100644 (file)
@@ -558,12 +558,12 @@ static int xennet_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
        spin_unlock_irq(&np->tx_lock);
 
-       return 0;
+       return NETDEV_TX_OK;
 
  drop:
        dev->stats.tx_dropped++;
        dev_kfree_skb(skb);
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 static int xennet_close(struct net_device *dev)
index 5a4ad15..0c44135 100644 (file)
@@ -239,7 +239,7 @@ out:
  * Actually probing is superfluous but we're paranoid.
  */
 
-int __init xtsonic_probe(struct platform_device *pdev)
+int __devinit xtsonic_probe(struct platform_device *pdev)
 {
        struct net_device *dev;
        struct sonic_local *lp;
index 3c7a505..c3722b4 100644 (file)
@@ -827,7 +827,7 @@ static int yellowfin_start_xmit(struct sk_buff *skb, struct net_device *dev)
                        if (skb_padto(skb, len)) {
                                yp->tx_skbuff[entry] = NULL;
                                netif_wake_queue(dev);
-                               return 0;
+                               return NETDEV_TX_OK;
                        }
                }
        }
@@ -881,7 +881,7 @@ static int yellowfin_start_xmit(struct sk_buff *skb, struct net_device *dev)
                printk(KERN_DEBUG "%s: Yellowfin transmit frame #%d queued in slot %d.\n",
                           dev->name, yp->cur_tx, entry);
        }
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 /* The interrupt handler does all of the Rx thread work and cleans up
index 0a6992d..7f9e141 100644 (file)
@@ -546,7 +546,7 @@ static int znet_send_packet(struct sk_buff *skb, struct net_device *dev)
 
        if (length < ETH_ZLEN) {
                if (skb_padto(skb, ETH_ZLEN))
-                       return 0;
+                       return NETDEV_TX_OK;
                length = ETH_ZLEN;
        }
 
@@ -600,7 +600,7 @@ static int znet_send_packet(struct sk_buff *skb, struct net_device *dev)
                  printk(KERN_DEBUG "%s: Transmitter queued, length %d.\n", dev->name, length);
        }
        dev_kfree_skb(skb);
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 /* The ZNET interrupt handler. */
index 5d610cb..0f0e0b9 100644 (file)
@@ -1134,7 +1134,7 @@ static const struct file_operations ccio_proc_bitmap_fops = {
        .llseek = seq_lseek,
        .release = single_release,
 };
-#endif
+#endif /* CONFIG_PROC_FS */
 
 /**
  * ccio_find_ioc - Find the ioc in the ioc_list
@@ -1568,14 +1568,15 @@ static int __init ccio_probe(struct parisc_device *dev)
        /* if this fails, no I/O cards will work, so may as well bug */
        BUG_ON(dev->dev.platform_data == NULL);
        HBA_DATA(dev->dev.platform_data)->iommu = ioc;
-       
+
+#ifdef CONFIG_PROC_FS
        if (ioc_count == 0) {
                proc_create(MODULE_NAME, 0, proc_runway_root,
                            &ccio_proc_info_fops);
                proc_create(MODULE_NAME"-bitmap", 0, proc_runway_root,
                            &ccio_proc_bitmap_fops);
        }
-
+#endif
        ioc_count++;
 
        parisc_has_iommu();
index 52ae0b1..c590974 100644 (file)
@@ -353,7 +353,7 @@ static unsigned int dino_startup_irq(unsigned int irq)
        return 0;
 }
 
-static struct hw_interrupt_type dino_interrupt_type = {
+static struct irq_chip dino_interrupt_type = {
        .typename       = "GSC-PCI",
        .startup        = dino_startup_irq,
        .shutdown       = dino_disable_irq,
@@ -1019,22 +1019,22 @@ static int __init dino_probe(struct parisc_device *dev)
        ** It's not used to avoid chicken/egg problems
        ** with configuration accessor functions.
        */
-       bus = pci_scan_bus_parented(&dev->dev, dino_current_bus,
-                                   &dino_cfg_ops, NULL);
+       dino_dev->hba.hba_bus = bus = pci_scan_bus_parented(&dev->dev,
+                        dino_current_bus, &dino_cfg_ops, NULL);
+
        if(bus) {
-               pci_bus_add_devices(bus);
                /* This code *depends* on scanning being single threaded
                 * if it isn't, this global bus number count will fail
                 */
                dino_current_bus = bus->subordinate + 1;
                pci_bus_assign_resources(bus);
+               pci_bus_add_devices(bus);
        } else {
-               printk(KERN_ERR "ERROR: failed to scan PCI bus on %s (probably duplicate bus number %d)\n",
+               printk(KERN_ERR "ERROR: failed to scan PCI bus on %s (duplicate bus number %d?)\n",
                       dev_name(&dev->dev), dino_current_bus);
                /* increment the bus number in case of duplicates */
                dino_current_bus++;
        }
-       dino_dev->hba.hba_bus = bus;
        return 0;
 }
 
index 5b89f40..5122074 100644 (file)
@@ -188,7 +188,7 @@ static unsigned int eisa_startup_irq(unsigned int irq)
        return 0;
 }
 
-static struct hw_interrupt_type eisa_interrupt_type = {
+static struct irq_chip eisa_interrupt_type = {
        .typename =     "EISA",
        .startup =      eisa_startup_irq,
        .shutdown =     eisa_disable_irq,
index d336329..647adc9 100644 (file)
@@ -148,7 +148,7 @@ static unsigned int gsc_asic_startup_irq(unsigned int irq)
        return 0;
 }
 
-static struct hw_interrupt_type gsc_asic_interrupt_type = {
+static struct irq_chip gsc_asic_interrupt_type = {
        .typename =     "GSC-ASIC",
        .startup =      gsc_asic_startup_irq,
        .shutdown =     gsc_asic_disable_irq,
@@ -158,7 +158,7 @@ static struct hw_interrupt_type gsc_asic_interrupt_type = {
        .end =          no_end_irq,
 };
 
-int gsc_assign_irq(struct hw_interrupt_type *type, void *data)
+int gsc_assign_irq(struct irq_chip *type, void *data)
 {
        static int irq = GSC_IRQ_BASE;
        struct irq_desc *desc;
index 762a1ba..b9d7bfb 100644 (file)
@@ -38,7 +38,7 @@ struct gsc_asic {
 int gsc_common_setup(struct parisc_device *parent, struct gsc_asic *gsc_asic);
 int gsc_alloc_irq(struct gsc_irq *dev);                        /* dev needs an irq */
 int gsc_claim_irq(struct gsc_irq *dev, int irq);       /* dev needs this irq */
-int gsc_assign_irq(struct hw_interrupt_type *type, void *data);
+int gsc_assign_irq(struct irq_chip *type, void *data);
 int gsc_find_local_irq(unsigned int irq, int *global_irq, int limit);
 void gsc_fixup_irqs(struct parisc_device *parent, void *ctrl,
                void (*choose)(struct parisc_device *child, void *ctrl));
index 4a9cc92..88e3335 100644 (file)
@@ -729,7 +729,7 @@ static int iosapic_set_affinity_irq(unsigned int irq,
 }
 #endif
 
-static struct hw_interrupt_type iosapic_interrupt_type = {
+static struct irq_chip iosapic_interrupt_type = {
        .typename =     "IO-SAPIC-level",
        .startup =      iosapic_startup_irq,
        .shutdown =     iosapic_disable_irq,
index 59fbbf1..ede6146 100644 (file)
@@ -980,28 +980,38 @@ static void
 lba_pat_resources(struct parisc_device *pa_dev, struct lba_device *lba_dev)
 {
        unsigned long bytecnt;
-       pdc_pat_cell_mod_maddr_block_t pa_pdc_cell;     /* PA_VIEW */
-       pdc_pat_cell_mod_maddr_block_t io_pdc_cell;     /* IO_VIEW */
        long io_count;
        long status;    /* PDC return status */
        long pa_count;
+       pdc_pat_cell_mod_maddr_block_t *pa_pdc_cell;    /* PA_VIEW */
+       pdc_pat_cell_mod_maddr_block_t *io_pdc_cell;    /* IO_VIEW */
        int i;
 
+       pa_pdc_cell = kzalloc(sizeof(pdc_pat_cell_mod_maddr_block_t), GFP_KERNEL);
+       if (!pa_pdc_cell)
+               return;
+
+       io_pdc_cell = kzalloc(sizeof(pdc_pat_cell_mod_maddr_block_t), GFP_KERNEL);
+       if (!pa_pdc_cell) {
+               kfree(pa_pdc_cell);
+               return;
+       }
+
        /* return cell module (IO view) */
        status = pdc_pat_cell_module(&bytecnt, pa_dev->pcell_loc, pa_dev->mod_index,
-                               PA_VIEW, pa_pdc_cell);
-       pa_count = pa_pdc_cell.mod[1];
+                               PA_VIEW, pa_pdc_cell);
+       pa_count = pa_pdc_cell->mod[1];
 
        status |= pdc_pat_cell_module(&bytecnt, pa_dev->pcell_loc, pa_dev->mod_index,
-                               IO_VIEW, &io_pdc_cell);
-       io_count = io_pdc_cell.mod[1];
+                               IO_VIEW, io_pdc_cell);
+       io_count = io_pdc_cell->mod[1];
 
        /* We've already done this once for device discovery...*/
        if (status != PDC_OK) {
                panic("pdc_pat_cell_module() call failed for LBA!\n");
        }
 
-       if (PAT_GET_ENTITY(pa_pdc_cell.mod_info) != PAT_ENTITY_LBA) {
+       if (PAT_GET_ENTITY(pa_pdc_cell->mod_info) != PAT_ENTITY_LBA) {
                panic("pdc_pat_cell_module() entity returned != PAT_ENTITY_LBA!\n");
        }
 
@@ -1016,8 +1026,8 @@ lba_pat_resources(struct parisc_device *pa_dev, struct lba_device *lba_dev)
                } *p, *io;
                struct resource *r;
 
-               p = (void *) &(pa_pdc_cell.mod[2+i*3]);
-               io = (void *) &(io_pdc_cell.mod[2+i*3]);
+               p = (void *) &(pa_pdc_cell->mod[2+i*3]);
+               io = (void *) &(io_pdc_cell->mod[2+i*3]);
 
                /* Convert the PAT range data to PCI "struct resource" */
                switch(p->type & 0xff) {
@@ -1096,6 +1106,9 @@ lba_pat_resources(struct parisc_device *pa_dev, struct lba_device *lba_dev)
                        break;
                }
        }
+
+       kfree(pa_pdc_cell);
+       kfree(io_pdc_cell);
 }
 #else
 /* keep compiler from complaining about missing declarations */
@@ -1509,10 +1522,6 @@ lba_driver_probe(struct parisc_device *dev)
        lba_bus = lba_dev->hba.hba_bus =
                pci_scan_bus_parented(&dev->dev, lba_dev->hba.bus_num.start,
                                cfg_ops, NULL);
-       if (lba_bus) {
-               lba_next_bus = lba_bus->subordinate + 1;
-               pci_bus_add_devices(lba_bus);
-       }
 
        /* This is in lieu of calling pci_assign_unassigned_resources() */
        if (is_pdc_pat()) {
@@ -1533,7 +1542,6 @@ lba_driver_probe(struct parisc_device *dev)
        }
        pci_enable_bridges(lba_bus);
 
-
        /*
        ** Once PCI register ops has walked the bus, access to config
        ** space is restricted. Avoids master aborts on config cycles.
@@ -1543,6 +1551,11 @@ lba_driver_probe(struct parisc_device *dev)
                lba_dev->flags |= LBA_FLAG_SKIP_PROBE;
        }
 
+       if (lba_bus) {
+               lba_next_bus = lba_bus->subordinate + 1;
+               pci_bus_add_devices(lba_bus);
+       }
+
        /* Whew! Finally done! Tell services we got this one covered. */
        return 0;
 }
index d46dd57..123d8fe 100644 (file)
@@ -2057,6 +2057,7 @@ void sba_directed_lmmio(struct parisc_device *pci_hba, struct resource *r)
                r->start = (base & ~1UL) | PCI_F_EXTEND;
                size = ~ READ_REG32(reg + LMMIO_DIRECT0_MASK);
                r->end = r->start + size;
+               r->flags = IORESOURCE_MEM;
        }
 }
 
@@ -2093,4 +2094,5 @@ void sba_distributed_lmmio(struct parisc_device *pci_hba, struct resource *r )
        size = (~READ_REG32(sba->sba_hpa + LMMIO_DIST_MASK)) / ROPES_PER_IOC;
        r->start += rope * (size + 1);  /* adjust base for this rope */
        r->end = r->start + size;
+       r->flags = IORESOURCE_MEM;
 }
index 33e5ade..675f04e 100644 (file)
@@ -325,7 +325,7 @@ static unsigned int superio_startup_irq(unsigned int irq)
        return 0;
 }
 
-static struct hw_interrupt_type superio_interrupt_type = {
+static struct irq_chip superio_interrupt_type = {
        .typename =     SUPERIO,
        .startup =      superio_startup_irq,
        .shutdown =     superio_disable_irq,
@@ -434,8 +434,8 @@ static void __init superio_parport_init(void)
                        0 /*base_hi*/,
                        PAR_IRQ, 
                        PARPORT_DMA_NONE /* dma */,
-                       NULL /*struct pci_dev* */),
-                       0 /* shared irq flags */ )
+                       NULL /*struct pci_dev* */,
+                       0 /* shared irq flags */))
 
                printk(KERN_WARNING PFX "Probing parallel port failed.\n");
 #endif /* CONFIG_PARPORT_PC */
index 1032d5f..2597145 100644 (file)
@@ -2907,6 +2907,7 @@ enum parport_pc_pci_cards {
        netmos_9755,
        netmos_9805,
        netmos_9815,
+       netmos_9901,
        quatech_sppxp100,
 };
 
@@ -2987,7 +2988,7 @@ static struct parport_pc_pci {
        /* netmos_9755 */               { 2, { { 0, 1 }, { 2, 3 },} },
        /* netmos_9805 */               { 1, { { 0, -1 }, } },
        /* netmos_9815 */               { 2, { { 0, -1 }, { 2, -1 }, } },
-
+       /* netmos_9901 */               { 1, { { 0, -1 }, } },
        /* quatech_sppxp100 */          { 1, { { 0, 1 }, } },
 };
 
@@ -3089,6 +3090,8 @@ static const struct pci_device_id parport_pc_pci_tbl[] = {
          PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9805 },
        { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9815,
          PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9815 },
+       { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9901,
+         0xA000, 0x2000, 0, 0, netmos_9901 },
        /* Quatech SPPXP-100 Parallel port PCI ExpressCard */
        { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_SPPXP_100,
          PCI_ANY_ID, PCI_ANY_ID, 0, 0, quatech_sppxp100 },
index e53eacd..5307542 100644 (file)
@@ -39,7 +39,6 @@
 #include <linux/sysdev.h>
 #include <asm/cacheflush.h>
 #include <asm/iommu.h>
-#include <asm/e820.h>
 #include "pci.h"
 
 #define ROOT_SIZE              VTD_PAGE_SIZE
 #define MAX_AGAW_WIDTH 64
 
 #define DOMAIN_MAX_ADDR(gaw) ((((u64)1) << gaw) - 1)
+#define DOMAIN_MAX_PFN(gaw)  ((((u64)1) << (gaw-VTD_PAGE_SHIFT)) - 1)
 
 #define IOVA_PFN(addr)         ((addr) >> PAGE_SHIFT)
 #define DMA_32BIT_PFN          IOVA_PFN(DMA_BIT_MASK(32))
 #define DMA_64BIT_PFN          IOVA_PFN(DMA_BIT_MASK(64))
 
-#ifndef PHYSICAL_PAGE_MASK
-#define PHYSICAL_PAGE_MASK PAGE_MASK
-#endif
+
+/* VT-d pages must always be _smaller_ than MM pages. Otherwise things
+   are never going to work. */
+static inline unsigned long dma_to_mm_pfn(unsigned long dma_pfn)
+{
+       return dma_pfn >> (PAGE_SHIFT - VTD_PAGE_SHIFT);
+}
+
+static inline unsigned long mm_to_dma_pfn(unsigned long mm_pfn)
+{
+       return mm_pfn << (PAGE_SHIFT - VTD_PAGE_SHIFT);
+}
+static inline unsigned long page_to_dma_pfn(struct page *pg)
+{
+       return mm_to_dma_pfn(page_to_pfn(pg));
+}
+static inline unsigned long virt_to_dma_pfn(void *p)
+{
+       return page_to_dma_pfn(virt_to_page(p));
+}
 
 /* global iommu list, set NULL for ignored DMAR units */
 static struct intel_iommu **g_iommus;
@@ -205,12 +222,17 @@ static inline void dma_set_pte_prot(struct dma_pte *pte, unsigned long prot)
 
 static inline u64 dma_pte_addr(struct dma_pte *pte)
 {
-       return (pte->val & VTD_PAGE_MASK);
+#ifdef CONFIG_64BIT
+       return pte->val & VTD_PAGE_MASK;
+#else
+       /* Must have a full atomic 64-bit read */
+       return  __cmpxchg64(pte, 0ULL, 0ULL) & VTD_PAGE_MASK;
+#endif
 }
 
-static inline void dma_set_pte_addr(struct dma_pte *pte, u64 addr)
+static inline void dma_set_pte_pfn(struct dma_pte *pte, unsigned long pfn)
 {
-       pte->val |= (addr & VTD_PAGE_MASK);
+       pte->val |= (uint64_t)pfn << VTD_PAGE_SHIFT;
 }
 
 static inline bool dma_pte_present(struct dma_pte *pte)
@@ -218,6 +240,11 @@ static inline bool dma_pte_present(struct dma_pte *pte)
        return (pte->val & 3) != 0;
 }
 
+static inline int first_pte_in_page(struct dma_pte *pte)
+{
+       return !((unsigned long)pte & ~VTD_PAGE_MASK);
+}
+
 /*
  * This domain is a statically identity mapping domain.
  *     1. This domain creats a static 1:1 mapping to all usable memory.
@@ -245,7 +272,6 @@ struct dmar_domain {
        struct iova_domain iovad;       /* iova's that belong to this domain */
 
        struct dma_pte  *pgd;           /* virtual address */
-       spinlock_t      mapping_lock;   /* page table lock */
        int             gaw;            /* max guest address width */
 
        /* adjusted guest address width, 0 is level 2 30-bit */
@@ -649,80 +675,78 @@ static inline int width_to_agaw(int width)
 
 static inline unsigned int level_to_offset_bits(int level)
 {
-       return (12 + (level - 1) * LEVEL_STRIDE);
+       return (level - 1) * LEVEL_STRIDE;
 }
 
-static inline int address_level_offset(u64 addr, int level)
+static inline int pfn_level_offset(unsigned long pfn, int level)
 {
-       return ((addr >> level_to_offset_bits(level)) & LEVEL_MASK);
+       return (pfn >> level_to_offset_bits(level)) & LEVEL_MASK;
 }
 
-static inline u64 level_mask(int level)
+static inline unsigned long level_mask(int level)
 {
-       return ((u64)-1 << level_to_offset_bits(level));
+       return -1UL << level_to_offset_bits(level);
 }
 
-static inline u64 level_size(int level)
+static inline unsigned long level_size(int level)
 {
-       return ((u64)1 << level_to_offset_bits(level));
+       return 1UL << level_to_offset_bits(level);
 }
 
-static inline u64 align_to_level(u64 addr, int level)
+static inline unsigned long align_to_level(unsigned long pfn, int level)
 {
-       return ((addr + level_size(level) - 1) & level_mask(level));
+       return (pfn + level_size(level) - 1) & level_mask(level);
 }
 
-static struct dma_pte * addr_to_dma_pte(struct dmar_domain *domain, u64 addr)
+static struct dma_pte *pfn_to_dma_pte(struct dmar_domain *domain,
+                                     unsigned long pfn)
 {
-       int addr_width = agaw_to_width(domain->agaw);
+       int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT;
        struct dma_pte *parent, *pte = NULL;
        int level = agaw_to_level(domain->agaw);
        int offset;
-       unsigned long flags;
 
        BUG_ON(!domain->pgd);
-
-       addr &= (((u64)1) << addr_width) - 1;
+       BUG_ON(addr_width < BITS_PER_LONG && pfn >> addr_width);
        parent = domain->pgd;
 
-       spin_lock_irqsave(&domain->mapping_lock, flags);
        while (level > 0) {
                void *tmp_page;
 
-               offset = address_level_offset(addr, level);
+               offset = pfn_level_offset(pfn, level);
                pte = &parent[offset];
                if (level == 1)
                        break;
 
                if (!dma_pte_present(pte)) {
+                       uint64_t pteval;
+
                        tmp_page = alloc_pgtable_page();
 
-                       if (!tmp_page) {
-                               spin_unlock_irqrestore(&domain->mapping_lock,
-                                       flags);
+                       if (!tmp_page)
                                return NULL;
+
+                       domain_flush_cache(domain, tmp_page, VTD_PAGE_SIZE);
+                       pteval = (virt_to_dma_pfn(tmp_page) << VTD_PAGE_SHIFT) | DMA_PTE_READ | DMA_PTE_WRITE;
+                       if (cmpxchg64(&pte->val, 0ULL, pteval)) {
+                               /* Someone else set it while we were thinking; use theirs. */
+                               free_pgtable_page(tmp_page);
+                       } else {
+                               dma_pte_addr(pte);
+                               domain_flush_cache(domain, pte, sizeof(*pte));
                        }
-                       domain_flush_cache(domain, tmp_page, PAGE_SIZE);
-                       dma_set_pte_addr(pte, virt_to_phys(tmp_page));
-                       /*
-                        * high level table always sets r/w, last level page
-                        * table control read/write
-                        */
-                       dma_set_pte_readable(pte);
-                       dma_set_pte_writable(pte);
-                       domain_flush_cache(domain, pte, sizeof(*pte));
                }
                parent = phys_to_virt(dma_pte_addr(pte));
                level--;
        }
 
-       spin_unlock_irqrestore(&domain->mapping_lock, flags);
        return pte;
 }
 
 /* return address's pte at specific level */
-static struct dma_pte *dma_addr_level_pte(struct dmar_domain *domain, u64 addr,
-               int level)
+static struct dma_pte *dma_pfn_level_pte(struct dmar_domain *domain,
+                                        unsigned long pfn,
+                                        int level)
 {
        struct dma_pte *parent, *pte = NULL;
        int total = agaw_to_level(domain->agaw);
@@ -730,7 +754,7 @@ static struct dma_pte *dma_addr_level_pte(struct dmar_domain *domain, u64 addr,
 
        parent = domain->pgd;
        while (level <= total) {
-               offset = address_level_offset(addr, total);
+               offset = pfn_level_offset(pfn, total);
                pte = &parent[offset];
                if (level == total)
                        return pte;
@@ -743,74 +767,82 @@ static struct dma_pte *dma_addr_level_pte(struct dmar_domain *domain, u64 addr,
        return NULL;
 }
 
-/* clear one page's page table */
-static void dma_pte_clear_one(struct dmar_domain *domain, u64 addr)
-{
-       struct dma_pte *pte = NULL;
-
-       /* get last level pte */
-       pte = dma_addr_level_pte(domain, addr, 1);
-
-       if (pte) {
-               dma_clear_pte(pte);
-               domain_flush_cache(domain, pte, sizeof(*pte));
-       }
-}
-
 /* clear last level pte, a tlb flush should be followed */
-static void dma_pte_clear_range(struct dmar_domain *domain, u64 start, u64 end)
+static void dma_pte_clear_range(struct dmar_domain *domain,
+                               unsigned long start_pfn,
+                               unsigned long last_pfn)
 {
-       int addr_width = agaw_to_width(domain->agaw);
-       int npages;
+       int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT;
+       struct dma_pte *first_pte, *pte;
+
+       BUG_ON(addr_width < BITS_PER_LONG && start_pfn >> addr_width);
+       BUG_ON(addr_width < BITS_PER_LONG && last_pfn >> addr_width);
 
-       start &= (((u64)1) << addr_width) - 1;
-       end &= (((u64)1) << addr_width) - 1;
-       /* in case it's partial page */
-       start &= PAGE_MASK;
-       end = PAGE_ALIGN(end);
-       npages = (end - start) / VTD_PAGE_SIZE;
+       /* we don't need lock here; nobody else touches the iova range */
+       while (start_pfn <= last_pfn) {
+               first_pte = pte = dma_pfn_level_pte(domain, start_pfn, 1);
+               if (!pte) {
+                       start_pfn = align_to_level(start_pfn + 1, 2);
+                       continue;
+               }
+               do { 
+                       dma_clear_pte(pte);
+                       start_pfn++;
+                       pte++;
+               } while (start_pfn <= last_pfn && !first_pte_in_page(pte));
 
-       /* we don't need lock here, nobody else touches the iova range */
-       while (npages--) {
-               dma_pte_clear_one(domain, start);
-               start += VTD_PAGE_SIZE;
+               domain_flush_cache(domain, first_pte,
+                                  (void *)pte - (void *)first_pte);
        }
 }
 
 /* free page table pages. last level pte should already be cleared */
 static void dma_pte_free_pagetable(struct dmar_domain *domain,
-       u64 start, u64 end)
+                                  unsigned long start_pfn,
+                                  unsigned long last_pfn)
 {
-       int addr_width = agaw_to_width(domain->agaw);
-       struct dma_pte *pte;
+       int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT;
+       struct dma_pte *first_pte, *pte;
        int total = agaw_to_level(domain->agaw);
        int level;
-       u64 tmp;
+       unsigned long tmp;
 
-       start &= (((u64)1) << addr_width) - 1;
-       end &= (((u64)1) << addr_width) - 1;
+       BUG_ON(addr_width < BITS_PER_LONG && start_pfn >> addr_width);
+       BUG_ON(addr_width < BITS_PER_LONG && last_pfn >> addr_width);
 
-       /* we don't need lock here, nobody else touches the iova range */
+       /* We don't need lock here; nobody else touches the iova range */
        level = 2;
        while (level <= total) {
-               tmp = align_to_level(start, level);
-               if (tmp >= end || (tmp + level_size(level) > end))
+               tmp = align_to_level(start_pfn, level);
+
+               /* If we can't even clear one PTE at this level, we're done */
+               if (tmp + level_size(level) - 1 > last_pfn)
                        return;
 
-               while (tmp < end) {
-                       pte = dma_addr_level_pte(domain, tmp, level);
-                       if (pte) {
-                               free_pgtable_page(
-                                       phys_to_virt(dma_pte_addr(pte)));
-                               dma_clear_pte(pte);
-                               domain_flush_cache(domain, pte, sizeof(*pte));
+               while (tmp + level_size(level) - 1 <= last_pfn) {
+                       first_pte = pte = dma_pfn_level_pte(domain, tmp, level);
+                       if (!pte) {
+                               tmp = align_to_level(tmp + 1, level + 1);
+                               continue;
                        }
-                       tmp += level_size(level);
+                       do {
+                               if (dma_pte_present(pte)) {
+                                       free_pgtable_page(phys_to_virt(dma_pte_addr(pte)));
+                                       dma_clear_pte(pte);
+                               }
+                               pte++;
+                               tmp += level_size(level);
+                       } while (!first_pte_in_page(pte) &&
+                                tmp + level_size(level) - 1 <= last_pfn);
+
+                       domain_flush_cache(domain, first_pte,
+                                          (void *)pte - (void *)first_pte);
+                       
                }
                level++;
        }
        /* free pgd */
-       if (start == 0 && end >= ((((u64)1) << addr_width) - 1)) {
+       if (start_pfn == 0 && last_pfn == DOMAIN_MAX_PFN(domain->gaw)) {
                free_pgtable_page(domain->pgd);
                domain->pgd = NULL;
        }
@@ -1036,11 +1068,11 @@ static void iommu_flush_dev_iotlb(struct dmar_domain *domain,
 }
 
 static void iommu_flush_iotlb_psi(struct intel_iommu *iommu, u16 did,
-                                 u64 addr, unsigned int pages)
+                                 unsigned long pfn, unsigned int pages)
 {
        unsigned int mask = ilog2(__roundup_pow_of_two(pages));
+       uint64_t addr = (uint64_t)pfn << VTD_PAGE_SHIFT;
 
-       BUG_ON(addr & (~VTD_PAGE_MASK));
        BUG_ON(pages == 0);
 
        /*
@@ -1055,7 +1087,12 @@ static void iommu_flush_iotlb_psi(struct intel_iommu *iommu, u16 did,
        else
                iommu->flush.flush_iotlb(iommu, did, addr, mask,
                                                DMA_TLB_PSI_FLUSH);
-       if (did)
+
+       /*
+        * In caching mode, domain ID 0 is reserved for non-present to present
+        * mapping flush. Device IOTLB doesn't need to be flushed in this case.
+        */
+       if (!cap_caching_mode(iommu->cap) || did)
                iommu_flush_dev_iotlb(iommu->domains[did], addr, mask);
 }
 
@@ -1280,7 +1317,6 @@ static void dmar_init_reserved_ranges(void)
        struct pci_dev *pdev = NULL;
        struct iova *iova;
        int i;
-       u64 addr, size;
 
        init_iova_domain(&reserved_iova_list, DMA_32BIT_PFN);
 
@@ -1303,12 +1339,9 @@ static void dmar_init_reserved_ranges(void)
                        r = &pdev->resource[i];
                        if (!r->flags || !(r->flags & IORESOURCE_MEM))
                                continue;
-                       addr = r->start;
-                       addr &= PHYSICAL_PAGE_MASK;
-                       size = r->end - addr;
-                       size = PAGE_ALIGN(size);
-                       iova = reserve_iova(&reserved_iova_list, IOVA_PFN(addr),
-                               IOVA_PFN(size + addr) - 1);
+                       iova = reserve_iova(&reserved_iova_list,
+                                           IOVA_PFN(r->start),
+                                           IOVA_PFN(r->end));
                        if (!iova)
                                printk(KERN_ERR "Reserve iova failed\n");
                }
@@ -1342,7 +1375,6 @@ static int domain_init(struct dmar_domain *domain, int guest_width)
        unsigned long sagaw;
 
        init_iova_domain(&domain->iovad, DMA_32BIT_PFN);
-       spin_lock_init(&domain->mapping_lock);
        spin_lock_init(&domain->iommu_lock);
 
        domain_reserve_special_ranges(domain);
@@ -1389,7 +1421,6 @@ static void domain_exit(struct dmar_domain *domain)
 {
        struct dmar_drhd_unit *drhd;
        struct intel_iommu *iommu;
-       u64 end;
 
        /* Domain 0 is reserved, so dont process it */
        if (!domain)
@@ -1398,14 +1429,12 @@ static void domain_exit(struct dmar_domain *domain)
        domain_remove_dev_info(domain);
        /* destroy iovas */
        put_iova_domain(&domain->iovad);
-       end = DOMAIN_MAX_ADDR(domain->gaw);
-       end = end & (~PAGE_MASK);
 
        /* clear ptes */
-       dma_pte_clear_range(domain, 0, end);
+       dma_pte_clear_range(domain, 0, DOMAIN_MAX_PFN(domain->gaw));
 
        /* free page tables */
-       dma_pte_free_pagetable(domain, 0, end);
+       dma_pte_free_pagetable(domain, 0, DOMAIN_MAX_PFN(domain->gaw));
 
        for_each_active_iommu(iommu, drhd)
                if (test_bit(iommu->seq_id, &domain->iommu_bmp))
@@ -1619,42 +1648,86 @@ static int domain_context_mapped(struct pci_dev *pdev)
                                             tmp->devfn);
 }
 
-static int
-domain_page_mapping(struct dmar_domain *domain, dma_addr_t iova,
-                       u64 hpa, size_t size, int prot)
+static int __domain_mapping(struct dmar_domain *domain, unsigned long iov_pfn,
+                           struct scatterlist *sg, unsigned long phys_pfn,
+                           unsigned long nr_pages, int prot)
 {
-       u64 start_pfn, end_pfn;
-       struct dma_pte *pte;
-       int index;
-       int addr_width = agaw_to_width(domain->agaw);
+       struct dma_pte *first_pte = NULL, *pte = NULL;
+       phys_addr_t uninitialized_var(pteval);
+       int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT;
+       unsigned long sg_res;
 
-       hpa &= (((u64)1) << addr_width) - 1;
+       BUG_ON(addr_width < BITS_PER_LONG && (iov_pfn + nr_pages - 1) >> addr_width);
 
        if ((prot & (DMA_PTE_READ|DMA_PTE_WRITE)) == 0)
                return -EINVAL;
-       iova &= PAGE_MASK;
-       start_pfn = ((u64)hpa) >> VTD_PAGE_SHIFT;
-       end_pfn = (VTD_PAGE_ALIGN(((u64)hpa) + size)) >> VTD_PAGE_SHIFT;
-       index = 0;
-       while (start_pfn < end_pfn) {
-               pte = addr_to_dma_pte(domain, iova + VTD_PAGE_SIZE * index);
-               if (!pte)
-                       return -ENOMEM;
+
+       prot &= DMA_PTE_READ | DMA_PTE_WRITE | DMA_PTE_SNP;
+
+       if (sg)
+               sg_res = 0;
+       else {
+               sg_res = nr_pages + 1;
+               pteval = ((phys_addr_t)phys_pfn << VTD_PAGE_SHIFT) | prot;
+       }
+
+       while (nr_pages--) {
+               uint64_t tmp;
+
+               if (!sg_res) {
+                       sg_res = (sg->offset + sg->length + VTD_PAGE_SIZE - 1) >> VTD_PAGE_SHIFT;
+                       sg->dma_address = ((dma_addr_t)iov_pfn << VTD_PAGE_SHIFT) + sg->offset;
+                       sg->dma_length = sg->length;
+                       pteval = page_to_phys(sg_page(sg)) | prot;
+               }
+               if (!pte) {
+                       first_pte = pte = pfn_to_dma_pte(domain, iov_pfn);
+                       if (!pte)
+                               return -ENOMEM;
+               }
                /* We don't need lock here, nobody else
                 * touches the iova range
                 */
-               BUG_ON(dma_pte_addr(pte));
-               dma_set_pte_addr(pte, start_pfn << VTD_PAGE_SHIFT);
-               dma_set_pte_prot(pte, prot);
-               if (prot & DMA_PTE_SNP)
-                       dma_set_pte_snp(pte);
-               domain_flush_cache(domain, pte, sizeof(*pte));
-               start_pfn++;
-               index++;
+               tmp = cmpxchg64_local(&pte->val, 0ULL, pteval);
+               if (tmp) {
+                       static int dumps = 5;
+                       printk(KERN_CRIT "ERROR: DMA PTE for vPFN 0x%lx already set (to %llx not %llx)\n",
+                              iov_pfn, tmp, (unsigned long long)pteval);
+                       if (dumps) {
+                               dumps--;
+                               debug_dma_dump_mappings(NULL);
+                       }
+                       WARN_ON(1);
+               }
+               pte++;
+               if (!nr_pages || first_pte_in_page(pte)) {
+                       domain_flush_cache(domain, first_pte,
+                                          (void *)pte - (void *)first_pte);
+                       pte = NULL;
+               }
+               iov_pfn++;
+               pteval += VTD_PAGE_SIZE;
+               sg_res--;
+               if (!sg_res)
+                       sg = sg_next(sg);
        }
        return 0;
 }
 
+static inline int domain_sg_mapping(struct dmar_domain *domain, unsigned long iov_pfn,
+                                   struct scatterlist *sg, unsigned long nr_pages,
+                                   int prot)
+{
+       return __domain_mapping(domain, iov_pfn, sg, 0, nr_pages, prot);
+}
+
+static inline int domain_pfn_mapping(struct dmar_domain *domain, unsigned long iov_pfn,
+                                    unsigned long phys_pfn, unsigned long nr_pages,
+                                    int prot)
+{
+       return __domain_mapping(domain, iov_pfn, NULL, phys_pfn, nr_pages, prot);
+}
+
 static void iommu_detach_dev(struct intel_iommu *iommu, u8 bus, u8 devfn)
 {
        if (!iommu)
@@ -1845,58 +1918,61 @@ error:
 
 static int iommu_identity_mapping;
 
+static int iommu_domain_identity_map(struct dmar_domain *domain,
+                                    unsigned long long start,
+                                    unsigned long long end)
+{
+       unsigned long first_vpfn = start >> VTD_PAGE_SHIFT;
+       unsigned long last_vpfn = end >> VTD_PAGE_SHIFT;
+
+       if (!reserve_iova(&domain->iovad, dma_to_mm_pfn(first_vpfn),
+                         dma_to_mm_pfn(last_vpfn))) {
+               printk(KERN_ERR "IOMMU: reserve iova failed\n");
+               return -ENOMEM;
+       }
+
+       pr_debug("Mapping reserved region %llx-%llx for domain %d\n",
+                start, end, domain->id);
+       /*
+        * RMRR range might have overlap with physical memory range,
+        * clear it first
+        */
+       dma_pte_clear_range(domain, first_vpfn, last_vpfn);
+
+       return domain_pfn_mapping(domain, first_vpfn, first_vpfn,
+                                 last_vpfn - first_vpfn + 1,
+                                 DMA_PTE_READ|DMA_PTE_WRITE);
+}
+
 static int iommu_prepare_identity_map(struct pci_dev *pdev,
                                      unsigned long long start,
                                      unsigned long long end)
 {
        struct dmar_domain *domain;
-       unsigned long size;
-       unsigned long long base;
        int ret;
 
        printk(KERN_INFO
-               "IOMMU: Setting identity map for device %s [0x%Lx - 0x%Lx]\n",
-               pci_name(pdev), start, end);
-       if (iommu_identity_mapping)
-               domain = si_domain;
-       else
-               /* page table init */
-               domain = get_domain_for_dev(pdev, DEFAULT_DOMAIN_ADDRESS_WIDTH);
+              "IOMMU: Setting identity map for device %s [0x%Lx - 0x%Lx]\n",
+              pci_name(pdev), start, end);
+
+       domain = get_domain_for_dev(pdev, DEFAULT_DOMAIN_ADDRESS_WIDTH);
        if (!domain)
                return -ENOMEM;
 
-       /* The address might not be aligned */
-       base = start & PAGE_MASK;
-       size = end - base;
-       size = PAGE_ALIGN(size);
-       if (!reserve_iova(&domain->iovad, IOVA_PFN(base),
-                       IOVA_PFN(base + size) - 1)) {
-               printk(KERN_ERR "IOMMU: reserve iova failed\n");
-               ret = -ENOMEM;
-               goto error;
-       }
-
-       pr_debug("Mapping reserved region %lx@%llx for %s\n",
-               size, base, pci_name(pdev));
-       /*
-        * RMRR range might have overlap with physical memory range,
-        * clear it first
-        */
-       dma_pte_clear_range(domain, base, base + size);
-
-       ret = domain_page_mapping(domain, base, base, size,
-               DMA_PTE_READ|DMA_PTE_WRITE);
+       ret = iommu_domain_identity_map(domain, start, end);
        if (ret)
                goto error;
 
        /* context entry init */
        ret = domain_context_mapping(domain, pdev, CONTEXT_TT_MULTI_LEVEL);
-       if (!ret)
-               return 0;
-error:
+       if (ret)
+               goto error;
+
+       return 0;
+
+ error:
        domain_exit(domain);
        return ret;
-
 }
 
 static inline int iommu_prepare_rmrr_dev(struct dmar_rmrr_unit *rmrr,
@@ -1908,64 +1984,6 @@ static inline int iommu_prepare_rmrr_dev(struct dmar_rmrr_unit *rmrr,
                rmrr->end_address + 1);
 }
 
-#ifdef CONFIG_DMAR_GFX_WA
-struct iommu_prepare_data {
-       struct pci_dev *pdev;
-       int ret;
-};
-
-static int __init iommu_prepare_work_fn(unsigned long start_pfn,
-                                        unsigned long end_pfn, void *datax)
-{
-       struct iommu_prepare_data *data;
-
-       data = (struct iommu_prepare_data *)datax;
-
-       data->ret = iommu_prepare_identity_map(data->pdev,
-                               start_pfn<<PAGE_SHIFT, end_pfn<<PAGE_SHIFT);
-       return data->ret;
-
-}
-
-static int __init iommu_prepare_with_active_regions(struct pci_dev *pdev)
-{
-       int nid;
-       struct iommu_prepare_data data;
-
-       data.pdev = pdev;
-       data.ret = 0;
-
-       for_each_online_node(nid) {
-               work_with_active_regions(nid, iommu_prepare_work_fn, &data);
-               if (data.ret)
-                       return data.ret;
-       }
-       return data.ret;
-}
-
-static void __init iommu_prepare_gfx_mapping(void)
-{
-       struct pci_dev *pdev = NULL;
-       int ret;
-
-       for_each_pci_dev(pdev) {
-               if (pdev->dev.archdata.iommu == DUMMY_DEVICE_DOMAIN_INFO ||
-                               !IS_GFX_DEVICE(pdev))
-                       continue;
-               printk(KERN_INFO "IOMMU: gfx device %s 1-1 mapping\n",
-                       pci_name(pdev));
-               ret = iommu_prepare_with_active_regions(pdev);
-               if (ret)
-                       printk(KERN_ERR "IOMMU: mapping reserved region failed\n");
-       }
-}
-#else /* !CONFIG_DMAR_GFX_WA */
-static inline void iommu_prepare_gfx_mapping(void)
-{
-       return;
-}
-#endif
-
 #ifdef CONFIG_DMAR_FLOPPY_WA
 static inline void iommu_prepare_isa(void)
 {
@@ -1976,12 +1994,12 @@ static inline void iommu_prepare_isa(void)
        if (!pdev)
                return;
 
-       printk(KERN_INFO "IOMMU: Prepare 0-16M unity mapping for LPC\n");
+       printk(KERN_INFO "IOMMU: Prepare 0-16MiB unity mapping for LPC\n");
        ret = iommu_prepare_identity_map(pdev, 0, 16*1024*1024);
 
        if (ret)
-               printk(KERN_ERR "IOMMU: Failed to create 0-64M identity map, "
-                       "floppy might not work\n");
+               printk(KERN_ERR "IOMMU: Failed to create 0-16MiB identity map; "
+                      "floppy might not work\n");
 
 }
 #else
@@ -2009,16 +2027,30 @@ static int __init init_context_pass_through(void)
 }
 
 static int md_domain_init(struct dmar_domain *domain, int guest_width);
+
+static int __init si_domain_work_fn(unsigned long start_pfn,
+                                   unsigned long end_pfn, void *datax)
+{
+       int *ret = datax;
+
+       *ret = iommu_domain_identity_map(si_domain,
+                                        (uint64_t)start_pfn << PAGE_SHIFT,
+                                        (uint64_t)end_pfn << PAGE_SHIFT);
+       return *ret;
+
+}
+
 static int si_domain_init(void)
 {
        struct dmar_drhd_unit *drhd;
        struct intel_iommu *iommu;
-       int ret = 0;
+       int nid, ret = 0;
 
        si_domain = alloc_domain();
        if (!si_domain)
                return -EFAULT;
 
+       pr_debug("Identity mapping domain is domain %d\n", si_domain->id);
 
        for_each_active_iommu(iommu, drhd) {
                ret = iommu_attach_domain(si_domain, iommu);
@@ -2035,6 +2067,12 @@ static int si_domain_init(void)
 
        si_domain->flags = DOMAIN_FLAG_STATIC_IDENTITY;
 
+       for_each_online_node(nid) {
+               work_with_active_regions(nid, si_domain_work_fn, &ret);
+               if (ret)
+                       return ret;
+       }
+
        return 0;
 }
 
@@ -2081,7 +2119,6 @@ static int domain_add_dev_info(struct dmar_domain *domain,
 
 static int iommu_prepare_static_identity_mapping(void)
 {
-       int i;
        struct pci_dev *pdev = NULL;
        int ret;
 
@@ -2089,20 +2126,14 @@ static int iommu_prepare_static_identity_mapping(void)
        if (ret)
                return -EFAULT;
 
-       printk(KERN_INFO "IOMMU: Setting identity map:\n");
        for_each_pci_dev(pdev) {
-               for (i = 0; i < e820.nr_map; i++) {
-                       struct e820entry *ei = &e820.map[i];
-
-                       if (ei->type == E820_RAM) {
-                               ret = iommu_prepare_identity_map(pdev,
-                                       ei->addr, ei->addr + ei->size);
-                               if (ret)  {
-                                       printk(KERN_INFO "1:1 mapping to one domain failed.\n");
-                                       return -EFAULT;
-                               }
-                       }
-               }
+               printk(KERN_INFO "IOMMU: identity mapping for device %s\n",
+                      pci_name(pdev));
+
+               ret = domain_context_mapping(si_domain, pdev,
+                                            CONTEXT_TT_MULTI_LEVEL);
+               if (ret)
+                       return ret;
                ret = domain_add_dev_info(si_domain, pdev);
                if (ret)
                        return ret;
@@ -2293,8 +2324,6 @@ int __init init_dmars(void)
                        }
                }
 
-               iommu_prepare_gfx_mapping();
-
                iommu_prepare_isa();
        }
 
@@ -2339,50 +2368,40 @@ error:
        return ret;
 }
 
-static inline u64 aligned_size(u64 host_addr, size_t size)
-{
-       u64 addr;
-       addr = (host_addr & (~PAGE_MASK)) + size;
-       return PAGE_ALIGN(addr);
-}
-
-struct iova *
-iommu_alloc_iova(struct dmar_domain *domain, size_t size, u64 end)
+static inline unsigned long aligned_nrpages(unsigned long host_addr,
+                                           size_t size)
 {
-       struct iova *piova;
+       host_addr &= ~PAGE_MASK;
+       host_addr += size + PAGE_SIZE - 1;
 
-       /* Make sure it's in range */
-       end = min_t(u64, DOMAIN_MAX_ADDR(domain->gaw), end);
-       if (!size || (IOVA_START_ADDR + size > end))
-               return NULL;
-
-       piova = alloc_iova(&domain->iovad,
-                       size >> PAGE_SHIFT, IOVA_PFN(end), 1);
-       return piova;
+       return host_addr >> VTD_PAGE_SHIFT;
 }
 
-static struct iova *
-__intel_alloc_iova(struct device *dev, struct dmar_domain *domain,
-                  size_t size, u64 dma_mask)
+static struct iova *intel_alloc_iova(struct device *dev,
+                                    struct dmar_domain *domain,
+                                    unsigned long nrpages, uint64_t dma_mask)
 {
        struct pci_dev *pdev = to_pci_dev(dev);
        struct iova *iova = NULL;
 
-       if (dma_mask <= DMA_BIT_MASK(32) || dmar_forcedac)
-               iova = iommu_alloc_iova(domain, size, dma_mask);
-       else {
+       /* Restrict dma_mask to the width that the iommu can handle */
+       dma_mask = min_t(uint64_t, DOMAIN_MAX_ADDR(domain->gaw), dma_mask);
+
+       if (!dmar_forcedac && dma_mask > DMA_BIT_MASK(32)) {
                /*
                 * First try to allocate an io virtual address in
                 * DMA_BIT_MASK(32) and if that fails then try allocating
                 * from higher range
                 */
-               iova = iommu_alloc_iova(domain, size, DMA_BIT_MASK(32));
-               if (!iova)
-                       iova = iommu_alloc_iova(domain, size, dma_mask);
-       }
-
-       if (!iova) {
-               printk(KERN_ERR"Allocating iova for %s failed", pci_name(pdev));
+               iova = alloc_iova(&domain->iovad, nrpages,
+                                 IOVA_PFN(DMA_BIT_MASK(32)), 1);
+               if (iova)
+                       return iova;
+       }
+       iova = alloc_iova(&domain->iovad, nrpages, IOVA_PFN(dma_mask), 1);
+       if (unlikely(!iova)) {
+               printk(KERN_ERR "Allocating %ld-page iova for %s failed",
+                      nrpages, pci_name(pdev));
                return NULL;
        }
 
@@ -2485,14 +2504,12 @@ static dma_addr_t __intel_map_single(struct device *hwdev, phys_addr_t paddr,
                return 0;
 
        iommu = domain_get_iommu(domain);
-       size = aligned_size((u64)paddr, size);
+       size = aligned_nrpages(paddr, size);
 
-       iova = __intel_alloc_iova(hwdev, domain, size, pdev->dma_mask);
+       iova = intel_alloc_iova(hwdev, domain, size, pdev->dma_mask);
        if (!iova)
                goto error;
 
-       start_paddr = (phys_addr_t)iova->pfn_lo << PAGE_SHIFT;
-
        /*
         * Check if DMAR supports zero-length reads on write only
         * mappings..
@@ -2508,20 +2525,20 @@ static dma_addr_t __intel_map_single(struct device *hwdev, phys_addr_t paddr,
         * might have two guest_addr mapping to the same host paddr, but this
         * is not a big problem
         */
-       ret = domain_page_mapping(domain, start_paddr,
-                                 ((u64)paddr) & PHYSICAL_PAGE_MASK,
-                                 size, prot);
+       ret = domain_pfn_mapping(domain, mm_to_dma_pfn(iova->pfn_lo),
+                                paddr >> VTD_PAGE_SHIFT, size, prot);
        if (ret)
                goto error;
 
        /* it's a non-present to present mapping. Only flush if caching mode */
        if (cap_caching_mode(iommu->cap))
-               iommu_flush_iotlb_psi(iommu, 0, start_paddr,
-                                     size >> VTD_PAGE_SHIFT);
+               iommu_flush_iotlb_psi(iommu, 0, mm_to_dma_pfn(iova->pfn_lo), size);
        else
                iommu_flush_write_buffer(iommu);
 
-       return start_paddr + ((u64)paddr & (~PAGE_MASK));
+       start_paddr = (phys_addr_t)iova->pfn_lo << PAGE_SHIFT;
+       start_paddr += paddr & ~PAGE_MASK;
+       return start_paddr;
 
 error:
        if (iova)
@@ -2614,7 +2631,7 @@ static void intel_unmap_page(struct device *dev, dma_addr_t dev_addr,
 {
        struct pci_dev *pdev = to_pci_dev(dev);
        struct dmar_domain *domain;
-       unsigned long start_addr;
+       unsigned long start_pfn, last_pfn;
        struct iova *iova;
        struct intel_iommu *iommu;
 
@@ -2627,22 +2644,25 @@ static void intel_unmap_page(struct device *dev, dma_addr_t dev_addr,
        iommu = domain_get_iommu(domain);
 
        iova = find_iova(&domain->iovad, IOVA_PFN(dev_addr));
-       if (!iova)
+       if (WARN_ONCE(!iova, "Driver unmaps unmatched page at PFN %llx\n",
+                     (unsigned long long)dev_addr))
                return;
 
-       start_addr = iova->pfn_lo << PAGE_SHIFT;
-       size = aligned_size((u64)dev_addr, size);
+       start_pfn = mm_to_dma_pfn(iova->pfn_lo);
+       last_pfn = mm_to_dma_pfn(iova->pfn_hi + 1) - 1;
 
-       pr_debug("Device %s unmapping: %zx@%llx\n",
-               pci_name(pdev), size, (unsigned long long)start_addr);
+       pr_debug("Device %s unmapping: pfn %lx-%lx\n",
+                pci_name(pdev), start_pfn, last_pfn);
 
        /*  clear the whole page */
-       dma_pte_clear_range(domain, start_addr, start_addr + size);
+       dma_pte_clear_range(domain, start_pfn, last_pfn);
+
        /* free page tables */
-       dma_pte_free_pagetable(domain, start_addr, start_addr + size);
+       dma_pte_free_pagetable(domain, start_pfn, last_pfn);
+
        if (intel_iommu_strict) {
-               iommu_flush_iotlb_psi(iommu, domain->id, start_addr,
-                                     size >> VTD_PAGE_SHIFT);
+               iommu_flush_iotlb_psi(iommu, domain->id, start_pfn,
+                                     last_pfn - start_pfn + 1);
                /* free iova */
                __free_iova(&domain->iovad, iova);
        } else {
@@ -2700,14 +2720,10 @@ static void intel_unmap_sg(struct device *hwdev, struct scatterlist *sglist,
                           int nelems, enum dma_data_direction dir,
                           struct dma_attrs *attrs)
 {
-       int i;
        struct pci_dev *pdev = to_pci_dev(hwdev);
        struct dmar_domain *domain;
-       unsigned long start_addr;
+       unsigned long start_pfn, last_pfn;
        struct iova *iova;
-       size_t size = 0;
-       phys_addr_t addr;
-       struct scatterlist *sg;
        struct intel_iommu *iommu;
 
        if (iommu_no_mapping(pdev))
@@ -2719,22 +2735,21 @@ static void intel_unmap_sg(struct device *hwdev, struct scatterlist *sglist,
        iommu = domain_get_iommu(domain);
 
        iova = find_iova(&domain->iovad, IOVA_PFN(sglist[0].dma_address));
-       if (!iova)
+       if (WARN_ONCE(!iova, "Driver unmaps unmatched sglist at PFN %llx\n",
+                     (unsigned long long)sglist[0].dma_address))
                return;
-       for_each_sg(sglist, sg, nelems, i) {
-               addr = page_to_phys(sg_page(sg)) + sg->offset;
-               size += aligned_size((u64)addr, sg->length);
-       }
 
-       start_addr = iova->pfn_lo << PAGE_SHIFT;
+       start_pfn = mm_to_dma_pfn(iova->pfn_lo);
+       last_pfn = mm_to_dma_pfn(iova->pfn_hi + 1) - 1;
 
        /*  clear the whole page */
-       dma_pte_clear_range(domain, start_addr, start_addr + size);
+       dma_pte_clear_range(domain, start_pfn, last_pfn);
+
        /* free page tables */
-       dma_pte_free_pagetable(domain, start_addr, start_addr + size);
+       dma_pte_free_pagetable(domain, start_pfn, last_pfn);
 
-       iommu_flush_iotlb_psi(iommu, domain->id, start_addr,
-                             size >> VTD_PAGE_SHIFT);
+       iommu_flush_iotlb_psi(iommu, domain->id, start_pfn,
+                             (last_pfn - start_pfn + 1));
 
        /* free iova */
        __free_iova(&domain->iovad, iova);
@@ -2757,17 +2772,16 @@ static int intel_nontranslate_map_sg(struct device *hddev,
 static int intel_map_sg(struct device *hwdev, struct scatterlist *sglist, int nelems,
                        enum dma_data_direction dir, struct dma_attrs *attrs)
 {
-       phys_addr_t addr;
        int i;
        struct pci_dev *pdev = to_pci_dev(hwdev);
        struct dmar_domain *domain;
        size_t size = 0;
        int prot = 0;
-       size_t offset = 0;
+       size_t offset_pfn = 0;
        struct iova *iova = NULL;
        int ret;
        struct scatterlist *sg;
-       unsigned long start_addr;
+       unsigned long start_vpfn;
        struct intel_iommu *iommu;
 
        BUG_ON(dir == DMA_NONE);
@@ -2780,12 +2794,10 @@ static int intel_map_sg(struct device *hwdev, struct scatterlist *sglist, int ne
 
        iommu = domain_get_iommu(domain);
 
-       for_each_sg(sglist, sg, nelems, i) {
-               addr = page_to_phys(sg_page(sg)) + sg->offset;
-               size += aligned_size((u64)addr, sg->length);
-       }
+       for_each_sg(sglist, sg, nelems, i)
+               size += aligned_nrpages(sg->offset, sg->length);
 
-       iova = __intel_alloc_iova(hwdev, domain, size, pdev->dma_mask);
+       iova = intel_alloc_iova(hwdev, domain, size, pdev->dma_mask);
        if (!iova) {
                sglist->dma_length = 0;
                return 0;
@@ -2801,35 +2813,24 @@ static int intel_map_sg(struct device *hwdev, struct scatterlist *sglist, int ne
        if (dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL)
                prot |= DMA_PTE_WRITE;
 
-       start_addr = iova->pfn_lo << PAGE_SHIFT;
-       offset = 0;
-       for_each_sg(sglist, sg, nelems, i) {
-               addr = page_to_phys(sg_page(sg)) + sg->offset;
-               size = aligned_size((u64)addr, sg->length);
-               ret = domain_page_mapping(domain, start_addr + offset,
-                                         ((u64)addr) & PHYSICAL_PAGE_MASK,
-                                         size, prot);
-               if (ret) {
-                       /*  clear the page */
-                       dma_pte_clear_range(domain, start_addr,
-                                 start_addr + offset);
-                       /* free page tables */
-                       dma_pte_free_pagetable(domain, start_addr,
-                                 start_addr + offset);
-                       /* free iova */
-                       __free_iova(&domain->iovad, iova);
-                       return 0;
-               }
-               sg->dma_address = start_addr + offset +
-                               ((u64)addr & (~PAGE_MASK));
-               sg->dma_length = sg->length;
-               offset += size;
+       start_vpfn = mm_to_dma_pfn(iova->pfn_lo);
+
+       ret = domain_sg_mapping(domain, start_vpfn, sglist, mm_to_dma_pfn(size), prot);
+       if (unlikely(ret)) {
+               /*  clear the page */
+               dma_pte_clear_range(domain, start_vpfn,
+                                   start_vpfn + size - 1);
+               /* free page tables */
+               dma_pte_free_pagetable(domain, start_vpfn,
+                                      start_vpfn + size - 1);
+               /* free iova */
+               __free_iova(&domain->iovad, iova);
+               return 0;
        }
 
        /* it's a non-present to present mapping. Only flush if caching mode */
        if (cap_caching_mode(iommu->cap))
-               iommu_flush_iotlb_psi(iommu, 0, start_addr,
-                                     offset >> VTD_PAGE_SHIFT);
+               iommu_flush_iotlb_psi(iommu, 0, start_vpfn, offset_pfn);
        else
                iommu_flush_write_buffer(iommu);
 
@@ -3334,7 +3335,6 @@ static int md_domain_init(struct dmar_domain *domain, int guest_width)
        int adjust_width;
 
        init_iova_domain(&domain->iovad, DMA_32BIT_PFN);
-       spin_lock_init(&domain->mapping_lock);
        spin_lock_init(&domain->iommu_lock);
 
        domain_reserve_special_ranges(domain);
@@ -3388,8 +3388,6 @@ static void iommu_free_vm_domain(struct dmar_domain *domain)
 
 static void vm_domain_exit(struct dmar_domain *domain)
 {
-       u64 end;
-
        /* Domain 0 is reserved, so dont process it */
        if (!domain)
                return;
@@ -3397,14 +3395,12 @@ static void vm_domain_exit(struct dmar_domain *domain)
        vm_domain_remove_all_dev_info(domain);
        /* destroy iovas */
        put_iova_domain(&domain->iovad);
-       end = DOMAIN_MAX_ADDR(domain->gaw);
-       end = end & (~VTD_PAGE_MASK);
 
        /* clear ptes */
-       dma_pte_clear_range(domain, 0, end);
+       dma_pte_clear_range(domain, 0, DOMAIN_MAX_PFN(domain->gaw));
 
        /* free page tables */
-       dma_pte_free_pagetable(domain, 0, end);
+       dma_pte_free_pagetable(domain, 0, DOMAIN_MAX_PFN(domain->gaw));
 
        iommu_free_vm_domain(domain);
        free_domain_mem(domain);
@@ -3513,7 +3509,7 @@ static int intel_iommu_map_range(struct iommu_domain *domain,
        if ((iommu_prot & IOMMU_CACHE) && dmar_domain->iommu_snooping)
                prot |= DMA_PTE_SNP;
 
-       max_addr = (iova & VTD_PAGE_MASK) + VTD_PAGE_ALIGN(size);
+       max_addr = iova + size;
        if (dmar_domain->max_addr < max_addr) {
                int min_agaw;
                u64 end;
@@ -3531,8 +3527,11 @@ static int intel_iommu_map_range(struct iommu_domain *domain,
                }
                dmar_domain->max_addr = max_addr;
        }
-
-       ret = domain_page_mapping(dmar_domain, iova, hpa, size, prot);
+       /* Round up size to next multiple of PAGE_SIZE, if it and
+          the low bits of hpa would take us onto the next page */
+       size = aligned_nrpages(hpa, size);
+       ret = domain_pfn_mapping(dmar_domain, iova >> VTD_PAGE_SHIFT,
+                                hpa >> VTD_PAGE_SHIFT, size, prot);
        return ret;
 }
 
@@ -3540,15 +3539,12 @@ static void intel_iommu_unmap_range(struct iommu_domain *domain,
                                    unsigned long iova, size_t size)
 {
        struct dmar_domain *dmar_domain = domain->priv;
-       dma_addr_t base;
 
-       /* The address might not be aligned */
-       base = iova & VTD_PAGE_MASK;
-       size = VTD_PAGE_ALIGN(size);
-       dma_pte_clear_range(dmar_domain, base, base + size);
+       dma_pte_clear_range(dmar_domain, iova >> VTD_PAGE_SHIFT,
+                           (iova + size - 1) >> VTD_PAGE_SHIFT);
 
-       if (dmar_domain->max_addr == base + size)
-               dmar_domain->max_addr = base;
+       if (dmar_domain->max_addr == iova + size)
+               dmar_domain->max_addr = iova;
 }
 
 static phys_addr_t intel_iommu_iova_to_phys(struct iommu_domain *domain,
@@ -3558,7 +3554,7 @@ static phys_addr_t intel_iommu_iova_to_phys(struct iommu_domain *domain,
        struct dma_pte *pte;
        u64 phys = 0;
 
-       pte = addr_to_dma_pte(dmar_domain, iova);
+       pte = pfn_to_dma_pte(dmar_domain, iova >> VTD_PAGE_SHIFT);
        if (pte)
                phys = dma_pte_addr(pte);
 
index 2287116..46dd440 100644 (file)
@@ -1,9 +1,19 @@
 /*
- * Copyright (c) 2006, Intel Corporation.
+ * Copyright Â© 2006-2009, Intel Corporation.
  *
- * This file is released under the GPLv2.
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307 USA.
  *
- * Copyright (C) 2006-2008 Intel Corporation
  * Author: Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com>
  */
 
@@ -123,7 +133,15 @@ move_left:
        /* Insert the new_iova into domain rbtree by holding writer lock */
        /* Add new node and rebalance tree. */
        {
-               struct rb_node **entry = &((prev)), *parent = NULL;
+               struct rb_node **entry, *parent = NULL;
+
+               /* If we have 'prev', it's a valid place to start the
+                  insertion. Otherwise, start from the root. */
+               if (prev)
+                       entry = &prev;
+               else
+                       entry = &iovad->rbroot.rb_node;
+
                /* Figure out where to put new node */
                while (*entry) {
                        struct iova *this = container_of(*entry,
index 659421d..d4ad50d 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * vrc4171_card.c, NEC VRC4171 Card Controller driver for Socket Services.
  *
- * Copyright (C) 2003-2005  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ * Copyright (C) 2003-2005  Yoichi Yuasa <yuasa@linux-mips.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
@@ -32,7 +32,7 @@
 #include "i82365.h"
 
 MODULE_DESCRIPTION("NEC VRC4171 Card Controllers driver for Socket Services");
-MODULE_AUTHOR("Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>");
+MODULE_AUTHOR("Yoichi Yuasa <yuasa@linux-mips.org>");
 MODULE_LICENSE("GPL");
 
 #define CARD_MAX_SLOTS         2
index 812f038..9b3c158 100644 (file)
@@ -6,7 +6,7 @@
  *     NEC VRC4173 CARDU driver for Socket Services
  *     (This device doesn't support CardBus. it is supporting only 16bit PC Card.)
  *
- * Copyright 2002,2003 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ * Copyright 2002,2003 Yoichi Yuasa <yuasa@linux-mips.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
@@ -41,7 +41,7 @@
 #include "vrc4173_cardu.h"
 
 MODULE_DESCRIPTION("NEC VRC4173 CARDU driver for Socket Services");
-MODULE_AUTHOR("Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>");
+MODULE_AUTHOR("Yoichi Yuasa <yuasa@linux-mips.org>");
 MODULE_LICENSE("GPL");
 
 static int vrc4173_cardu_slots;
index 7d77c74..a7d9601 100644 (file)
@@ -5,7 +5,7 @@
  * BRIEF MODULE DESCRIPTION
  *     Include file for NEC VRC4173 CARDU.
  *
- * Copyright 2002 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ * Copyright 2002 Yoichi Yuasa <yuasa@linux-mips.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
index 7232fe7..46dad12 100644 (file)
@@ -355,6 +355,7 @@ config EEEPC_LAPTOP
        depends on INPUT
        depends on EXPERIMENTAL
        depends on RFKILL || RFKILL = n
+       depends on HOTPLUG_PCI
        select BACKLIGHT_CLASS_DEVICE
        select HWMON
        ---help---
index 4207b26..ec560f1 100644 (file)
@@ -16,6 +16,8 @@
  *  GNU General Public License for more details.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/init.h>
@@ -31,6 +33,7 @@
 #include <linux/input.h>
 #include <linux/rfkill.h>
 #include <linux/pci.h>
+#include <linux/pci_hotplug.h>
 
 #define EEEPC_LAPTOP_VERSION   "0.1"
 
 #define EEEPC_HOTK_DEVICE_NAME "Hotkey"
 #define EEEPC_HOTK_HID         "ASUS010"
 
-#define EEEPC_LOG      EEEPC_HOTK_FILE ": "
-#define EEEPC_ERR      KERN_ERR        EEEPC_LOG
-#define EEEPC_WARNING  KERN_WARNING    EEEPC_LOG
-#define EEEPC_NOTICE   KERN_NOTICE     EEEPC_LOG
-#define EEEPC_INFO     KERN_INFO       EEEPC_LOG
 
 /*
  * Definitions for Asus EeePC
@@ -141,8 +139,10 @@ struct eeepc_hotk {
        u16 event_count[128];           /* count for each event */
        struct input_dev *inputdev;
        u16 *keycode_map;
-       struct rfkill *eeepc_wlan_rfkill;
-       struct rfkill *eeepc_bluetooth_rfkill;
+       struct rfkill *wlan_rfkill;
+       struct rfkill *bluetooth_rfkill;
+       struct rfkill *wwan3g_rfkill;
+       struct hotplug_slot *hotplug_slot;
 };
 
 /* The actual device the driver binds to */
@@ -213,6 +213,15 @@ static struct acpi_driver eeepc_hotk_driver = {
        },
 };
 
+/* PCI hotplug ops */
+static int eeepc_get_adapter_status(struct hotplug_slot *slot, u8 *value);
+
+static struct hotplug_slot_ops eeepc_hotplug_slot_ops = {
+       .owner = THIS_MODULE,
+       .get_adapter_status = eeepc_get_adapter_status,
+       .get_power_status = eeepc_get_adapter_status,
+};
+
 /* The backlight device /sys/class/backlight */
 static struct backlight_device *eeepc_backlight_device;
 
@@ -274,20 +283,20 @@ static int set_acpi(int cm, int value)
                if (method == NULL)
                        return -ENODEV;
                if (write_acpi_int(ehotk->handle, method, value, NULL))
-                       printk(EEEPC_WARNING "Error writing %s\n", method);
+                       pr_warning("Error writing %s\n", method);
        }
        return 0;
 }
 
 static int get_acpi(int cm)
 {
-       int value = -1;
+       int value = -ENODEV;
        if ((ehotk->cm_supported & (0x1 << cm))) {
                const char *method = cm_getv[cm];
                if (method == NULL)
                        return -ENODEV;
                if (read_acpi_int(ehotk->handle, method, &value))
-                       printk(EEEPC_WARNING "Error reading %s\n", method);
+                       pr_warning("Error reading %s\n", method);
        }
        return value;
 }
@@ -359,13 +368,19 @@ static ssize_t store_sys_acpi(int cm, const char *buf, size_t count)
 
        rv = parse_arg(buf, count, &value);
        if (rv > 0)
-               set_acpi(cm, value);
+               value = set_acpi(cm, value);
+       if (value < 0)
+               return value;
        return rv;
 }
 
 static ssize_t show_sys_acpi(int cm, char *buf)
 {
-       return sprintf(buf, "%d\n", get_acpi(cm));
+       int value = get_acpi(cm);
+
+       if (value < 0)
+               return value;
+       return sprintf(buf, "%d\n", value);
 }
 
 #define EEEPC_CREATE_DEVICE_ATTR(_name, _cm)                           \
@@ -539,6 +554,28 @@ static int eeepc_setkeycode(struct input_dev *dev, int scancode, int keycode)
        return -EINVAL;
 }
 
+static void cmsg_quirk(int cm, const char *name)
+{
+       int dummy;
+
+       /* Some BIOSes do not report cm although it is avaliable.
+          Check if cm_getv[cm] works and, if yes, assume cm should be set. */
+       if (!(ehotk->cm_supported & (1 << cm))
+           && !read_acpi_int(ehotk->handle, cm_getv[cm], &dummy)) {
+               pr_info("%s (%x) not reported by BIOS,"
+                       " enabling anyway\n", name, 1 << cm);
+               ehotk->cm_supported |= 1 << cm;
+       }
+}
+
+static void cmsg_quirks(void)
+{
+       cmsg_quirk(CM_ASL_LID, "LID");
+       cmsg_quirk(CM_ASL_TYPE, "TYPE");
+       cmsg_quirk(CM_ASL_PANELPOWER, "PANELPOWER");
+       cmsg_quirk(CM_ASL_TPD, "TPD");
+}
+
 static int eeepc_hotk_check(void)
 {
        const struct key_entry *key;
@@ -551,26 +588,24 @@ static int eeepc_hotk_check(void)
        if (ehotk->device->status.present) {
                if (write_acpi_int(ehotk->handle, "INIT", ehotk->init_flag,
                                    &buffer)) {
-                       printk(EEEPC_ERR "Hotkey initialization failed\n");
+                       pr_err("Hotkey initialization failed\n");
                        return -ENODEV;
                } else {
-                       printk(EEEPC_NOTICE "Hotkey init flags 0x%x\n",
-                              ehotk->init_flag);
+                       pr_notice("Hotkey init flags 0x%x\n", ehotk->init_flag);
                }
                /* get control methods supported */
                if (read_acpi_int(ehotk->handle, "CMSG"
                                   , &ehotk->cm_supported)) {
-                       printk(EEEPC_ERR
-                              "Get control methods supported failed\n");
+                       pr_err("Get control methods supported failed\n");
                        return -ENODEV;
                } else {
-                       printk(EEEPC_INFO
-                              "Get control methods supported: 0x%x\n",
-                              ehotk->cm_supported);
+                       cmsg_quirks();
+                       pr_info("Get control methods supported: 0x%x\n",
+                               ehotk->cm_supported);
                }
                ehotk->inputdev = input_allocate_device();
                if (!ehotk->inputdev) {
-                       printk(EEEPC_INFO "Unable to allocate input device\n");
+                       pr_info("Unable to allocate input device\n");
                        return 0;
                }
                ehotk->inputdev->name = "Asus EeePC extra buttons";
@@ -589,12 +624,12 @@ static int eeepc_hotk_check(void)
                }
                result = input_register_device(ehotk->inputdev);
                if (result) {
-                       printk(EEEPC_INFO "Unable to register input device\n");
+                       pr_info("Unable to register input device\n");
                        input_free_device(ehotk->inputdev);
                        return 0;
                }
        } else {
-               printk(EEEPC_ERR "Hotkey device not present, aborting\n");
+               pr_err("Hotkey device not present, aborting\n");
                return -EINVAL;
        }
        return 0;
@@ -612,6 +647,19 @@ static int notify_brn(void)
        return -1;
 }
 
+static int eeepc_get_adapter_status(struct hotplug_slot *hotplug_slot,
+                                   u8 *value)
+{
+       int val = get_acpi(CM_ASL_WLAN);
+
+       if (val == 1 || val == 0)
+               *value = val;
+       else
+               return -EINVAL;
+
+       return 0;
+}
+
 static void eeepc_rfkill_hotplug(void)
 {
        struct pci_dev *dev;
@@ -619,7 +667,7 @@ static void eeepc_rfkill_hotplug(void)
        bool blocked;
 
        if (!bus) {
-               printk(EEEPC_WARNING "Unable to find PCI bus 1?\n");
+               pr_warning("Unable to find PCI bus 1?\n");
                return;
        }
 
@@ -635,7 +683,7 @@ static void eeepc_rfkill_hotplug(void)
                if (dev) {
                        pci_bus_assign_resources(bus);
                        if (pci_bus_add_device(dev))
-                               printk(EEEPC_ERR "Unable to hotplug wifi\n");
+                               pr_err("Unable to hotplug wifi\n");
                }
        } else {
                dev = pci_get_slot(bus, 0);
@@ -645,7 +693,7 @@ static void eeepc_rfkill_hotplug(void)
                }
        }
 
-       rfkill_set_sw_state(ehotk->eeepc_wlan_rfkill, blocked);
+       rfkill_set_sw_state(ehotk->wlan_rfkill, blocked);
 }
 
 static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data)
@@ -718,8 +766,7 @@ static int eeepc_register_rfkill_notifier(char *node)
                                                     eeepc_rfkill_notify,
                                                     NULL);
                if (ACPI_FAILURE(status))
-                       printk(EEEPC_WARNING
-                              "Failed to register notify on %s\n", node);
+                       pr_warning("Failed to register notify on %s\n", node);
        } else
                return -ENODEV;
 
@@ -738,19 +785,66 @@ static void eeepc_unregister_rfkill_notifier(char *node)
                                                     ACPI_SYSTEM_NOTIFY,
                                                     eeepc_rfkill_notify);
                if (ACPI_FAILURE(status))
-                       printk(EEEPC_ERR
-                              "Error removing rfkill notify handler %s\n",
+                       pr_err("Error removing rfkill notify handler %s\n",
                                node);
        }
 }
 
+static void eeepc_cleanup_pci_hotplug(struct hotplug_slot *hotplug_slot)
+{
+       kfree(hotplug_slot->info);
+       kfree(hotplug_slot);
+}
+
+static int eeepc_setup_pci_hotplug(void)
+{
+       int ret = -ENOMEM;
+       struct pci_bus *bus = pci_find_bus(0, 1);
+
+       if (!bus) {
+               pr_err("Unable to find wifi PCI bus\n");
+               return -ENODEV;
+       }
+
+       ehotk->hotplug_slot = kzalloc(sizeof(struct hotplug_slot), GFP_KERNEL);
+       if (!ehotk->hotplug_slot)
+               goto error_slot;
+
+       ehotk->hotplug_slot->info = kzalloc(sizeof(struct hotplug_slot_info),
+                                           GFP_KERNEL);
+       if (!ehotk->hotplug_slot->info)
+               goto error_info;
+
+       ehotk->hotplug_slot->private = ehotk;
+       ehotk->hotplug_slot->release = &eeepc_cleanup_pci_hotplug;
+       ehotk->hotplug_slot->ops = &eeepc_hotplug_slot_ops;
+       eeepc_get_adapter_status(ehotk->hotplug_slot,
+                                &ehotk->hotplug_slot->info->adapter_status);
+
+       ret = pci_hp_register(ehotk->hotplug_slot, bus, 0, "eeepc-wifi");
+       if (ret) {
+               pr_err("Unable to register hotplug slot - %d\n", ret);
+               goto error_register;
+       }
+
+       return 0;
+
+error_register:
+       kfree(ehotk->hotplug_slot->info);
+error_info:
+       kfree(ehotk->hotplug_slot);
+       ehotk->hotplug_slot = NULL;
+error_slot:
+       return ret;
+}
+
 static int eeepc_hotk_add(struct acpi_device *device)
 {
        int result;
 
        if (!device)
                 return -EINVAL;
-       printk(EEEPC_NOTICE EEEPC_HOTK_NAME "\n");
+       pr_notice(EEEPC_HOTK_NAME "\n");
        ehotk = kzalloc(sizeof(struct eeepc_hotk), GFP_KERNEL);
        if (!ehotk)
                return -ENOMEM;
@@ -764,53 +858,8 @@ static int eeepc_hotk_add(struct acpi_device *device)
        if (result)
                goto ehotk_fail;
 
-       eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P6");
-       eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P7");
-
-       if (get_acpi(CM_ASL_WLAN) != -1) {
-               ehotk->eeepc_wlan_rfkill = rfkill_alloc("eeepc-wlan",
-                                                       &device->dev,
-                                                       RFKILL_TYPE_WLAN,
-                                                       &eeepc_rfkill_ops,
-                                                       (void *)CM_ASL_WLAN);
-
-               if (!ehotk->eeepc_wlan_rfkill)
-                       goto wlan_fail;
-
-               rfkill_init_sw_state(ehotk->eeepc_wlan_rfkill,
-                                    get_acpi(CM_ASL_WLAN) != 1);
-               result = rfkill_register(ehotk->eeepc_wlan_rfkill);
-               if (result)
-                       goto wlan_fail;
-       }
-
-       if (get_acpi(CM_ASL_BLUETOOTH) != -1) {
-               ehotk->eeepc_bluetooth_rfkill =
-                       rfkill_alloc("eeepc-bluetooth",
-                                    &device->dev,
-                                    RFKILL_TYPE_BLUETOOTH,
-                                    &eeepc_rfkill_ops,
-                                    (void *)CM_ASL_BLUETOOTH);
-
-               if (!ehotk->eeepc_bluetooth_rfkill)
-                       goto bluetooth_fail;
-
-               rfkill_init_sw_state(ehotk->eeepc_bluetooth_rfkill,
-                                    get_acpi(CM_ASL_BLUETOOTH) != 1);
-               result = rfkill_register(ehotk->eeepc_bluetooth_rfkill);
-               if (result)
-                       goto bluetooth_fail;
-       }
-
        return 0;
 
- bluetooth_fail:
-       rfkill_destroy(ehotk->eeepc_bluetooth_rfkill);
-       rfkill_unregister(ehotk->eeepc_wlan_rfkill);
- wlan_fail:
-       rfkill_destroy(ehotk->eeepc_wlan_rfkill);
-       eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P6");
-       eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P7");
  ehotk_fail:
        kfree(ehotk);
        ehotk = NULL;
@@ -823,16 +872,13 @@ static int eeepc_hotk_remove(struct acpi_device *device, int type)
        if (!device || !acpi_driver_data(device))
                 return -EINVAL;
 
-       eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P6");
-       eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P7");
-
        kfree(ehotk);
        return 0;
 }
 
 static int eeepc_hotk_resume(struct acpi_device *device)
 {
-       if (ehotk->eeepc_wlan_rfkill) {
+       if (ehotk->wlan_rfkill) {
                bool wlan;
 
                /* Workaround - it seems that _PTS disables the wireless
@@ -844,14 +890,13 @@ static int eeepc_hotk_resume(struct acpi_device *device)
                wlan = get_acpi(CM_ASL_WLAN);
                set_acpi(CM_ASL_WLAN, wlan);
 
-               rfkill_set_sw_state(ehotk->eeepc_wlan_rfkill,
-                                   wlan != 1);
+               rfkill_set_sw_state(ehotk->wlan_rfkill, wlan != 1);
 
                eeepc_rfkill_hotplug();
        }
 
-       if (ehotk->eeepc_bluetooth_rfkill)
-               rfkill_set_sw_state(ehotk->eeepc_bluetooth_rfkill,
+       if (ehotk->bluetooth_rfkill)
+               rfkill_set_sw_state(ehotk->bluetooth_rfkill,
                                    get_acpi(CM_ASL_BLUETOOTH) != 1);
 
        return 0;
@@ -973,10 +1018,16 @@ static void eeepc_backlight_exit(void)
 
 static void eeepc_rfkill_exit(void)
 {
-       if (ehotk->eeepc_wlan_rfkill)
-               rfkill_unregister(ehotk->eeepc_wlan_rfkill);
-       if (ehotk->eeepc_bluetooth_rfkill)
-               rfkill_unregister(ehotk->eeepc_bluetooth_rfkill);
+       eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P6");
+       eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P7");
+       if (ehotk->wlan_rfkill)
+               rfkill_unregister(ehotk->wlan_rfkill);
+       if (ehotk->bluetooth_rfkill)
+               rfkill_unregister(ehotk->bluetooth_rfkill);
+       if (ehotk->wwan3g_rfkill)
+               rfkill_unregister(ehotk->wwan3g_rfkill);
+       if (ehotk->hotplug_slot)
+               pci_hp_deregister(ehotk->hotplug_slot);
 }
 
 static void eeepc_input_exit(void)
@@ -1011,6 +1062,75 @@ static void __exit eeepc_laptop_exit(void)
        platform_driver_unregister(&platform_driver);
 }
 
+static int eeepc_new_rfkill(struct rfkill **rfkill,
+                           const char *name, struct device *dev,
+                           enum rfkill_type type, int cm)
+{
+       int result;
+
+       result = get_acpi(cm);
+       if (result < 0)
+               return result;
+
+       *rfkill = rfkill_alloc(name, dev, type,
+                              &eeepc_rfkill_ops, (void *)(unsigned long)cm);
+
+       if (!*rfkill)
+               return -EINVAL;
+
+       rfkill_init_sw_state(*rfkill, get_acpi(cm) != 1);
+       result = rfkill_register(*rfkill);
+       if (result) {
+               rfkill_destroy(*rfkill);
+               *rfkill = NULL;
+               return result;
+       }
+       return 0;
+}
+
+
+static int eeepc_rfkill_init(struct device *dev)
+{
+       int result = 0;
+
+       eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P6");
+       eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P7");
+
+       result = eeepc_new_rfkill(&ehotk->wlan_rfkill,
+                                 "eeepc-wlan", dev,
+                                 RFKILL_TYPE_WLAN, CM_ASL_WLAN);
+
+       if (result && result != -ENODEV)
+               goto exit;
+
+       result = eeepc_new_rfkill(&ehotk->bluetooth_rfkill,
+                                 "eeepc-bluetooth", dev,
+                                 RFKILL_TYPE_BLUETOOTH, CM_ASL_BLUETOOTH);
+
+       if (result && result != -ENODEV)
+               goto exit;
+
+       result = eeepc_new_rfkill(&ehotk->wwan3g_rfkill,
+                                 "eeepc-wwan3g", dev,
+                                 RFKILL_TYPE_WWAN, CM_ASL_3G);
+
+       if (result && result != -ENODEV)
+               goto exit;
+
+       result = eeepc_setup_pci_hotplug();
+       /*
+        * If we get -EBUSY then something else is handling the PCI hotplug -
+        * don't fail in this case
+        */
+       if (result == -EBUSY)
+               result = 0;
+
+exit:
+       if (result && result != -ENODEV)
+               eeepc_rfkill_exit();
+       return result;
+}
+
 static int eeepc_backlight_init(struct device *dev)
 {
        struct backlight_device *bd;
@@ -1018,8 +1138,7 @@ static int eeepc_backlight_init(struct device *dev)
        bd = backlight_device_register(EEEPC_HOTK_FILE, dev,
                                       NULL, &eeepcbl_ops);
        if (IS_ERR(bd)) {
-               printk(EEEPC_ERR
-                      "Could not register eeepc backlight device\n");
+               pr_err("Could not register eeepc backlight device\n");
                eeepc_backlight_device = NULL;
                return PTR_ERR(bd);
        }
@@ -1038,8 +1157,7 @@ static int eeepc_hwmon_init(struct device *dev)
 
        hwmon = hwmon_device_register(dev);
        if (IS_ERR(hwmon)) {
-               printk(EEEPC_ERR
-                      "Could not register eeepc hwmon device\n");
+               pr_err("Could not register eeepc hwmon device\n");
                eeepc_hwmon_device = NULL;
                return PTR_ERR(hwmon);
        }
@@ -1065,19 +1183,6 @@ static int __init eeepc_laptop_init(void)
                acpi_bus_unregister_driver(&eeepc_hotk_driver);
                return -ENODEV;
        }
-       dev = acpi_get_physical_device(ehotk->device->handle);
-
-       if (!acpi_video_backlight_support()) {
-               result = eeepc_backlight_init(dev);
-               if (result)
-                       goto fail_backlight;
-       } else
-               printk(EEEPC_INFO "Backlight controlled by ACPI video "
-                      "driver\n");
-
-       result = eeepc_hwmon_init(dev);
-       if (result)
-               goto fail_hwmon;
 
        eeepc_enable_camera();
 
@@ -1097,7 +1202,33 @@ static int __init eeepc_laptop_init(void)
                                    &platform_attribute_group);
        if (result)
                goto fail_sysfs;
+
+       dev = &platform_device->dev;
+
+       if (!acpi_video_backlight_support()) {
+               result = eeepc_backlight_init(dev);
+               if (result)
+                       goto fail_backlight;
+       } else
+               pr_info("Backlight controlled by ACPI video "
+                       "driver\n");
+
+       result = eeepc_hwmon_init(dev);
+       if (result)
+               goto fail_hwmon;
+
+       result = eeepc_rfkill_init(dev);
+       if (result)
+               goto fail_rfkill;
+
        return 0;
+fail_rfkill:
+       eeepc_hwmon_exit();
+fail_hwmon:
+       eeepc_backlight_exit();
+fail_backlight:
+       sysfs_remove_group(&platform_device->dev.kobj,
+                          &platform_attribute_group);
 fail_sysfs:
        platform_device_del(platform_device);
 fail_platform_device2:
@@ -1105,12 +1236,7 @@ fail_platform_device2:
 fail_platform_device1:
        platform_driver_unregister(&platform_driver);
 fail_platform_driver:
-       eeepc_hwmon_exit();
-fail_hwmon:
-       eeepc_backlight_exit();
-fail_backlight:
        eeepc_input_exit();
-       eeepc_rfkill_exit();
        return result;
 }
 
index aafd3e6..a118eb0 100644 (file)
@@ -1,8 +1,8 @@
 /*
  * Blackfin On-Chip Real Time Clock Driver
- *  Supports BF52[257]/BF53[123]/BF53[467]/BF54[24789]
+ *  Supports BF51x/BF52x/BF53[123]/BF53[467]/BF54x
  *
- * Copyright 2004-2008 Analog Devices Inc.
+ * Copyright 2004-2009 Analog Devices Inc.
  *
  * Enter bugs at http://blackfin.uclinux.org/
  *
@@ -363,7 +363,7 @@ static int __devinit bfin_rtc_probe(struct platform_device *pdev)
        struct bfin_rtc *rtc;
        struct device *dev = &pdev->dev;
        int ret = 0;
-       unsigned long timeout;
+       unsigned long timeout = jiffies + HZ;
 
        dev_dbg_stamp(dev);
 
@@ -374,32 +374,32 @@ static int __devinit bfin_rtc_probe(struct platform_device *pdev)
        platform_set_drvdata(pdev, rtc);
        device_init_wakeup(dev, 1);
 
+       /* Register our RTC with the RTC framework */
+       rtc->rtc_dev = rtc_device_register(pdev->name, dev, &bfin_rtc_ops,
+                                               THIS_MODULE);
+       if (unlikely(IS_ERR(rtc->rtc_dev))) {
+               ret = PTR_ERR(rtc->rtc_dev);
+               goto err;
+       }
+
        /* Grab the IRQ and init the hardware */
        ret = request_irq(IRQ_RTC, bfin_rtc_interrupt, IRQF_SHARED, pdev->name, dev);
        if (unlikely(ret))
-               goto err;
+               goto err_reg;
        /* sometimes the bootloader touched things, but the write complete was not
         * enabled, so let's just do a quick timeout here since the IRQ will not fire ...
         */
-       timeout = jiffies + HZ;
        while (bfin_read_RTC_ISTAT() & RTC_ISTAT_WRITE_PENDING)
                if (time_after(jiffies, timeout))
                        break;
        bfin_rtc_reset(dev, RTC_ISTAT_WRITE_COMPLETE);
        bfin_write_RTC_SWCNT(0);
 
-       /* Register our RTC with the RTC framework */
-       rtc->rtc_dev = rtc_device_register(pdev->name, dev, &bfin_rtc_ops, THIS_MODULE);
-       if (unlikely(IS_ERR(rtc->rtc_dev))) {
-               ret = PTR_ERR(rtc->rtc_dev);
-               goto err_irq;
-       }
-
        return 0;
 
- err_irq:
-       free_irq(IRQ_RTC, dev);
- err:
+err_reg:
+       rtc_device_unregister(rtc->rtc_dev);
+err:
        kfree(rtc);
        return ret;
 }
index f11297a..2c839d0 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  Driver for NEC VR4100 series Real Time Clock unit.
  *
- *  Copyright (C) 2003-2008  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *  Copyright (C) 2003-2008  Yoichi Yuasa <yuasa@linux-mips.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
@@ -33,7 +33,7 @@
 #include <asm/io.h>
 #include <asm/uaccess.h>
 
-MODULE_AUTHOR("Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>");
+MODULE_AUTHOR("Yoichi Yuasa <yuasa@linux-mips.org>");
 MODULE_DESCRIPTION("NEC VR4100 series RTC driver");
 MODULE_LICENSE("GPL v2");
 
index f370f8d..c63babe 100644 (file)
@@ -350,6 +350,8 @@ claw_tx(struct sk_buff *skb, struct net_device *dev)
        CLAW_DBF_TEXT_(4, trace, "clawtx%d", rc);
        if (rc)
                rc = NETDEV_TX_BUSY;
+       else
+               rc = NETDEV_TX_OK;
         return rc;
 }   /*  end of claw_tx */
 
index 222e473..38b5079 100644 (file)
@@ -880,7 +880,7 @@ static int ctcm_tx(struct sk_buff *skb, struct net_device *dev)
                                "%s(%s): NULL sk_buff passed",
                                        CTCM_FUNTAIL, dev->name);
                priv->stats.tx_dropped++;
-               return 0;
+               return NETDEV_TX_OK;
        }
        if (skb_headroom(skb) < (LL_HEADER_LENGTH + 2)) {
                CTCM_DBF_TEXT_(ERROR, CTC_DBF_ERROR,
@@ -888,7 +888,7 @@ static int ctcm_tx(struct sk_buff *skb, struct net_device *dev)
                        CTCM_FUNTAIL, dev->name, LL_HEADER_LENGTH + 2);
                dev_kfree_skb(skb);
                priv->stats.tx_dropped++;
-               return 0;
+               return NETDEV_TX_OK;
        }
 
        /*
@@ -901,7 +901,7 @@ static int ctcm_tx(struct sk_buff *skb, struct net_device *dev)
                priv->stats.tx_dropped++;
                priv->stats.tx_errors++;
                priv->stats.tx_carrier_errors++;
-               return 0;
+               return NETDEV_TX_OK;
        }
 
        if (ctcm_test_and_set_busy(dev))
@@ -910,7 +910,7 @@ static int ctcm_tx(struct sk_buff *skb, struct net_device *dev)
        dev->trans_start = jiffies;
        if (ctcm_transmit_skb(priv->channel[WRITE], skb) != 0)
                return NETDEV_TX_BUSY;
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 /* unmerged MPC variant of ctcm_tx */
@@ -1008,7 +1008,7 @@ done:
        if (do_debug)
                MPC_DBF_DEV_NAME(TRACE, dev, "exit");
 
-       return 0;       /* handle freeing of skb here */
+       return NETDEV_TX_OK;    /* handle freeing of skb here */
 }
 
 
index 8c67590..a70de9b 100644 (file)
@@ -1553,24 +1553,24 @@ __lcs_start_xmit(struct lcs_card *card, struct sk_buff *skb,
                 struct net_device *dev)
 {
        struct lcs_header *header;
-       int rc = 0;
+       int rc = NETDEV_TX_OK;
 
        LCS_DBF_TEXT(5, trace, "hardxmit");
        if (skb == NULL) {
                card->stats.tx_dropped++;
                card->stats.tx_errors++;
-               return 0;
+               return NETDEV_TX_OK;
        }
        if (card->state != DEV_STATE_UP) {
                dev_kfree_skb(skb);
                card->stats.tx_dropped++;
                card->stats.tx_errors++;
                card->stats.tx_carrier_errors++;
-               return 0;
+               return NETDEV_TX_OK;
        }
        if (skb->protocol == htons(ETH_P_IPV6)) {
                dev_kfree_skb(skb);
-               return 0;
+               return NETDEV_TX_OK;
        }
        netif_stop_queue(card->dev);
        spin_lock(&card->lock);
index 8c36eaf..bb1183a 100644 (file)
@@ -1376,14 +1376,14 @@ static int netiucv_tx(struct sk_buff *skb, struct net_device *dev)
        if (skb == NULL) {
                IUCV_DBF_TEXT(data, 2, "netiucv_tx: skb is NULL\n");
                privptr->stats.tx_dropped++;
-               return 0;
+               return NETDEV_TX_OK;
        }
        if (skb_headroom(skb) < NETIUCV_HDRLEN) {
                IUCV_DBF_TEXT(data, 2,
                        "netiucv_tx: skb_headroom < NETIUCV_HDRLEN\n");
                dev_kfree_skb(skb);
                privptr->stats.tx_dropped++;
-               return 0;
+               return NETDEV_TX_OK;
        }
 
        /**
@@ -1395,7 +1395,7 @@ static int netiucv_tx(struct sk_buff *skb, struct net_device *dev)
                privptr->stats.tx_dropped++;
                privptr->stats.tx_errors++;
                privptr->stats.tx_carrier_errors++;
-               return 0;
+               return NETDEV_TX_OK;
        }
 
        if (netiucv_test_and_set_busy(dev)) {
index 691cecd..2cfc338 100644 (file)
@@ -744,6 +744,7 @@ static int qeth_l2_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
                card->stats.tx_bytes += tx_bytes;
                if (new_skb != skb)
                        dev_kfree_skb_any(skb);
+               rc = NETDEV_TX_OK;
        } else {
                if (data_offset >= 0)
                        kmem_cache_free(qeth_core_header_cache, hdr);
index 5487240..048defa 100644 (file)
@@ -2793,6 +2793,7 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
                                card->perf_stats.sg_frags_sent += nr_frags + 1;
                        }
                }
+               rc = NETDEV_TX_OK;
        } else {
                if (data_offset >= 0)
                        kmem_cache_free(qeth_core_header_cache, hdr);
index 25a2032..70d060b 100644 (file)
@@ -1,4 +1,4 @@
-EXTRA_CFLAGS += -I$(TOPDIR)/drivers/net/cxgb3
+EXTRA_CFLAGS += -I$(srctree)/drivers/net/cxgb3
 
 cxgb3i-y := cxgb3i_init.o cxgb3i_iscsi.o cxgb3i_pdu.o cxgb3i_offload.o cxgb3i_ddp.o
 obj-$(CONFIG_SCSI_CXGB3_ISCSI) += cxgb3i.o
index 74369a3..c399f48 100644 (file)
@@ -13,6 +13,7 @@
 
 #include <linux/inet.h>
 #include <linux/crypto.h>
+#include <linux/if_vlan.h>
 #include <net/dst.h>
 #include <net/tcp.h>
 #include <scsi/scsi_cmnd.h>
@@ -184,6 +185,9 @@ static struct cxgb3i_hba *cxgb3i_hba_find_by_netdev(struct net_device *ndev)
        struct cxgb3i_adapter *snic;
        int i;
 
+       if (ndev->priv_flags & IFF_802_1Q_VLAN)
+               ndev = vlan_dev_real_dev(ndev);
+
        read_lock(&cxgb3i_snic_rwlock);
        list_for_each_entry(snic, &cxgb3i_snic_list, list_head) {
                for (i = 0; i < snic->hba_cnt; i++) {
index a840728..2c266c0 100644 (file)
@@ -473,16 +473,16 @@ static int __devinit fnic_probe(struct pci_dev *pdev,
         * limitation for the device.  Try 40-bit first, and
         * fail to 32-bit.
         */
-       err = pci_set_dma_mask(pdev, DMA_40BIT_MASK);
+       err = pci_set_dma_mask(pdev, DMA_BIT_MASK(40));
        if (err) {
-               err = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+               err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
                if (err) {
                        shost_printk(KERN_ERR, fnic->lport->host,
                                     "No usable DMA configuration "
                                     "aborting\n");
                        goto err_out_release_regions;
                }
-               err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
+               err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
                if (err) {
                        shost_printk(KERN_ERR, fnic->lport->host,
                                     "Unable to obtain 32-bit DMA "
@@ -490,7 +490,7 @@ static int __devinit fnic_probe(struct pci_dev *pdev,
                        goto err_out_release_regions;
                }
        } else {
-               err = pci_set_consistent_dma_mask(pdev, DMA_40BIT_MASK);
+               err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(40));
                if (err) {
                        shost_printk(KERN_ERR, fnic->lport->host,
                                     "Unable to obtain 40-bit DMA "
index eabf365..bfc9969 100644 (file)
@@ -245,7 +245,7 @@ static inline int fnic_queue_wq_copy_desc(struct fnic *fnic,
                                          struct vnic_wq_copy *wq,
                                          struct fnic_io_req *io_req,
                                          struct scsi_cmnd *sc,
-                                         u32 sg_count)
+                                         int sg_count)
 {
        struct scatterlist *sg;
        struct fc_rport *rport = starget_to_rport(scsi_target(sc->device));
@@ -260,9 +260,6 @@ static inline int fnic_queue_wq_copy_desc(struct fnic *fnic,
        char msg[2];
 
        if (sg_count) {
-               BUG_ON(sg_count < 0);
-               BUG_ON(sg_count > FNIC_MAX_SG_DESC_CNT);
-
                /* For each SGE, create a device desc entry */
                desc = io_req->sgl_list;
                for_each_sg(scsi_sglist(sc), sg, sg_count, i) {
@@ -344,7 +341,7 @@ int fnic_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
        struct fnic *fnic;
        struct vnic_wq_copy *wq;
        int ret;
-       u32 sg_count;
+       int sg_count;
        unsigned long flags;
        unsigned long ptr;
 
index 869a11b..9928704 100644 (file)
@@ -1095,9 +1095,14 @@ static void adapter_info_rsp(struct srp_event_struct *evt_struct)
                                MAX_INDIRECT_BUFS);
                        hostdata->host->sg_tablesize = MAX_INDIRECT_BUFS;
                }
+
+               if (hostdata->madapter_info.os_type == 3) {
+                       enable_fast_fail(hostdata);
+                       return;
+               }
        }
 
-       enable_fast_fail(hostdata);
+       send_srp_login(hostdata);
 }
 
 /**
index 2eee9e6..292c02f 100644 (file)
@@ -3670,13 +3670,14 @@ static void
 fc_bsg_goose_queue(struct fc_rport *rport)
 {
        int flagset;
+       unsigned long flags;
 
        if (!rport->rqst_q)
                return;
 
        get_device(&rport->dev);
 
-       spin_lock(rport->rqst_q->queue_lock);
+       spin_lock_irqsave(rport->rqst_q->queue_lock, flags);
        flagset = test_bit(QUEUE_FLAG_REENTER, &rport->rqst_q->queue_flags) &&
                  !test_bit(QUEUE_FLAG_REENTER, &rport->rqst_q->queue_flags);
        if (flagset)
@@ -3684,7 +3685,7 @@ fc_bsg_goose_queue(struct fc_rport *rport)
        __blk_run_queue(rport->rqst_q);
        if (flagset)
                queue_flag_clear(QUEUE_FLAG_REENTER, rport->rqst_q);
-       spin_unlock(rport->rqst_q->queue_lock);
+       spin_unlock_irqrestore(rport->rqst_q->queue_lock, flags);
 
        put_device(&rport->dev);
 }
index 8201387..ef142fd 100644 (file)
@@ -210,13 +210,11 @@ static void sg_put_dev(Sg_device *sdp);
 static int sg_allow_access(struct file *filp, unsigned char *cmd)
 {
        struct sg_fd *sfp = (struct sg_fd *)filp->private_data;
-       struct request_queue *q = sfp->parentdp->device->request_queue;
 
        if (sfp->parentdp->device->type == TYPE_SCANNER)
                return 0;
 
-       return blk_verify_command(&q->cmd_filter,
-                                 cmd, filp->f_mode & FMODE_WRITE);
+       return blk_verify_command(cmd, filp->f_mode & FMODE_WRITE);
 }
 
 static int
index 97f3158..27e84e4 100644 (file)
@@ -134,7 +134,7 @@ zalon_probe(struct parisc_device *dev)
 
        host = ncr_attach(&zalon7xx_template, unit, &device);
        if (!host)
-               goto fail;
+               return -ENODEV;
 
        if (request_irq(dev->irq, ncr53c8xx_intr, IRQF_SHARED, "zalon", host)) {
          dev_printk(KERN_ERR, &dev->dev, "irq problem with %d, detaching\n ",
index a07015d..6160e03 100644 (file)
@@ -759,6 +759,8 @@ static int pci_netmos_init(struct pci_dev *dev)
        /* subdevice 0x00PS means <P> parallel, <S> serial */
        unsigned int num_serial = dev->subsystem_device & 0xf;
 
+       if (dev->device == PCI_DEVICE_ID_NETMOS_9901)
+               return 0;
        if (dev->subsystem_vendor == PCI_VENDOR_ID_IBM &&
                        dev->subsystem_device == 0x0299)
                return 0;
@@ -3557,6 +3559,10 @@ static struct pci_device_id serial_pci_tbl[] = {
                PCI_VENDOR_ID_IBM, 0x0299,
                0, 0, pbn_b0_bt_2_115200 },
 
+       {       PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9901,
+               0xA000, 0x1000,
+               0, 0, pbn_b0_1_115200 },
+
        /*
         * These entries match devices with class COMMUNICATION_SERIAL,
         * COMMUNICATION_MODEM or COMMUNICATION_MULTISERIAL
index 0573f3b..dac550e 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  Driver for NEC VR4100 series Serial Interface Unit.
  *
- *  Copyright (C) 2004-2008  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *  Copyright (C) 2004-2008  Yoichi Yuasa <yuasa@linux-mips.org>
  *
  *  Based on drivers/serial/8250.c, by Russell King.
  *
index aa90ddb..8980a56 100644 (file)
@@ -514,6 +514,8 @@ static int __init uwire_probe(struct platform_device *pdev)
        /* the spi->mode bits understood by this driver: */
        master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
 
+       master->flags = SPI_MASTER_HALF_DUPLEX;
+
        master->bus_num = 2;    /* "official" */
        master->num_chipselect = 4;
        master->setup = uwire_setup;
index 2a5abc0..f1db395 100644 (file)
@@ -258,6 +258,11 @@ static void bitbang_work(struct work_struct *work)
        struct spi_bitbang      *bitbang =
                container_of(work, struct spi_bitbang, work);
        unsigned long           flags;
+       int                     do_setup = -1;
+       int                     (*setup_transfer)(struct spi_device *,
+                                       struct spi_transfer *);
+
+       setup_transfer = bitbang->setup_transfer;
 
        spin_lock_irqsave(&bitbang->lock, flags);
        bitbang->busy = 1;
@@ -269,8 +274,6 @@ static void bitbang_work(struct work_struct *work)
                unsigned                tmp;
                unsigned                cs_change;
                int                     status;
-               int                     (*setup_transfer)(struct spi_device *,
-                                               struct spi_transfer *);
 
                m = container_of(bitbang->queue.next, struct spi_message,
                                queue);
@@ -287,19 +290,19 @@ static void bitbang_work(struct work_struct *work)
                tmp = 0;
                cs_change = 1;
                status = 0;
-               setup_transfer = NULL;
 
                list_for_each_entry (t, &m->transfers, transfer_list) {
 
-                       /* override or restore speed and wordsize */
-                       if (t->speed_hz || t->bits_per_word) {
-                               setup_transfer = bitbang->setup_transfer;
+                       /* override speed or wordsize? */
+                       if (t->speed_hz || t->bits_per_word)
+                               do_setup = 1;
+
+                       /* init (-1) or override (1) transfer params */
+                       if (do_setup != 0) {
                                if (!setup_transfer) {
                                        status = -ENOPROTOOPT;
                                        break;
                                }
-                       }
-                       if (setup_transfer) {
                                status = setup_transfer(spi, t);
                                if (status < 0)
                                        break;
@@ -363,9 +366,10 @@ static void bitbang_work(struct work_struct *work)
                m->status = status;
                m->complete(m->context);
 
-               /* restore speed and wordsize */
-               if (setup_transfer)
+               /* restore speed and wordsize if it was overridden */
+               if (do_setup == 1)
                        setup_transfer(spi, NULL);
+               do_setup = 0;
 
                /* normally deactivate chipselect ... unless no error and
                 * cs_change has hinted that the next message will probably
index 5d869c4..606e7a4 100644 (file)
@@ -58,15 +58,20 @@ static unsigned long        minors[N_SPI_MINORS / BITS_PER_LONG];
 
 
 /* Bit masks for spi_device.mode management.  Note that incorrect
- * settings for CS_HIGH and 3WIRE can cause *lots* of trouble for other
- * devices on a shared bus:  CS_HIGH, because this device will be
- * active when it shouldn't be;  3WIRE, because when active it won't
- * behave as it should.
+ * settings for some settings can cause *lots* of trouble for other
+ * devices on a shared bus:
  *
- * REVISIT should changing those two modes be privileged?
+ *  - CS_HIGH ... this device will be active when it shouldn't be
+ *  - 3WIRE ... when active, it won't behave as it should
+ *  - NO_CS ... there will be no explicit message boundaries; this
+ *     is completely incompatible with the shared bus model
+ *  - READY ... transfers may proceed when they shouldn't.
+ *
+ * REVISIT should changing those flags be privileged?
  */
 #define SPI_MODE_MASK          (SPI_CPHA | SPI_CPOL | SPI_CS_HIGH \
-                               | SPI_LSB_FIRST | SPI_3WIRE | SPI_LOOP)
+                               | SPI_LSB_FIRST | SPI_3WIRE | SPI_LOOP \
+                               | SPI_NO_CS | SPI_READY)
 
 struct spidev_data {
        dev_t                   devt;
index 3fd3e3b..3c6feed 100644 (file)
@@ -49,29 +49,54 @@ static const u32 ipsflag_irq_shift[] = {
 
 static inline u32 ssb_irqflag(struct ssb_device *dev)
 {
-       return ssb_read32(dev, SSB_TPSFLAG) & SSB_TPSFLAG_BPFLAG;
+       u32 tpsflag = ssb_read32(dev, SSB_TPSFLAG);
+       if (tpsflag)
+               return ssb_read32(dev, SSB_TPSFLAG) & SSB_TPSFLAG_BPFLAG;
+       else
+               /* not irq supported */
+               return 0x3f;
+}
+
+static struct ssb_device *find_device(struct ssb_device *rdev, int irqflag)
+{
+       struct ssb_bus *bus = rdev->bus;
+       int i;
+       for (i = 0; i < bus->nr_devices; i++) {
+               struct ssb_device *dev;
+               dev = &(bus->devices[i]);
+               if (ssb_irqflag(dev) == irqflag)
+                       return dev;
+       }
+       return NULL;
 }
 
 /* Get the MIPS IRQ assignment for a specified device.
  * If unassigned, 0 is returned.
+ * If disabled, 5 is returned.
+ * If not supported, 6 is returned.
  */
 unsigned int ssb_mips_irq(struct ssb_device *dev)
 {
        struct ssb_bus *bus = dev->bus;
+       struct ssb_device *mdev = bus->mipscore.dev;
        u32 irqflag;
        u32 ipsflag;
        u32 tmp;
        unsigned int irq;
 
        irqflag = ssb_irqflag(dev);
+       if (irqflag == 0x3f)
+               return 6;
        ipsflag = ssb_read32(bus->mipscore.dev, SSB_IPSFLAG);
        for (irq = 1; irq <= 4; irq++) {
                tmp = ((ipsflag & ipsflag_irq_mask[irq]) >> ipsflag_irq_shift[irq]);
                if (tmp == irqflag)
                        break;
        }
-       if (irq == 5)
-               irq = 0;
+       if (irq == 5) {
+               if ((1 << irqflag) & ssb_read32(mdev, SSB_INTVEC))
+                       irq = 0;
+       }
 
        return irq;
 }
@@ -97,25 +122,56 @@ static void set_irq(struct ssb_device *dev, unsigned int irq)
        struct ssb_device *mdev = bus->mipscore.dev;
        u32 irqflag = ssb_irqflag(dev);
 
+       BUG_ON(oldirq == 6);
+
        dev->irq = irq + 2;
 
-       ssb_dprintk(KERN_INFO PFX
-                   "set_irq: core 0x%04x, irq %d => %d\n",
-                   dev->id.coreid, oldirq, irq);
        /* clear the old irq */
        if (oldirq == 0)
                ssb_write32(mdev, SSB_INTVEC, (~(1 << irqflag) & ssb_read32(mdev, SSB_INTVEC)));
-       else
+       else if (oldirq != 5)
                clear_irq(bus, oldirq);
 
        /* assign the new one */
        if (irq == 0) {
                ssb_write32(mdev, SSB_INTVEC, ((1 << irqflag) | ssb_read32(mdev, SSB_INTVEC)));
        } else {
+               u32 ipsflag = ssb_read32(mdev, SSB_IPSFLAG);
+               if ((ipsflag & ipsflag_irq_mask[irq]) != ipsflag_irq_mask[irq]) {
+                       u32 oldipsflag = (ipsflag & ipsflag_irq_mask[irq]) >> ipsflag_irq_shift[irq];
+                       struct ssb_device *olddev = find_device(dev, oldipsflag);
+                       if (olddev)
+                               set_irq(olddev, 0);
+               }
                irqflag <<= ipsflag_irq_shift[irq];
-               irqflag |= (ssb_read32(mdev, SSB_IPSFLAG) & ~ipsflag_irq_mask[irq]);
+               irqflag |= (ipsflag & ~ipsflag_irq_mask[irq]);
                ssb_write32(mdev, SSB_IPSFLAG, irqflag);
        }
+       ssb_dprintk(KERN_INFO PFX
+                   "set_irq: core 0x%04x, irq %d => %d\n",
+                   dev->id.coreid, oldirq+2, irq+2);
+}
+
+static void print_irq(struct ssb_device *dev, unsigned int irq)
+{
+       int i;
+       static const char *irq_name[] = {"2(S)", "3", "4", "5", "6", "D", "I"};
+       ssb_dprintk(KERN_INFO PFX
+               "core 0x%04x, irq :", dev->id.coreid);
+       for (i = 0; i <= 6; i++) {
+               ssb_dprintk(" %s%s", irq_name[i], i==irq?"*":" ");
+       }
+       ssb_dprintk("\n");
+}
+
+static void dump_irq(struct ssb_bus *bus)
+{
+       int i;
+       for (i = 0; i < bus->nr_devices; i++) {
+               struct ssb_device *dev;
+               dev = &(bus->devices[i]);
+               print_irq(dev, ssb_mips_irq(dev));
+       }
 }
 
 static void ssb_mips_serial_init(struct ssb_mipscore *mcore)
@@ -197,16 +253,23 @@ void ssb_mipscore_init(struct ssb_mipscore *mcore)
 
        /* Assign IRQs to all cores on the bus, start with irq line 2, because serial usually takes 1 */
        for (irq = 2, i = 0; i < bus->nr_devices; i++) {
+               int mips_irq;
                dev = &(bus->devices[i]);
-               dev->irq = ssb_mips_irq(dev) + 2;
+               mips_irq = ssb_mips_irq(dev);
+               if (mips_irq > 4)
+                       dev->irq = 0;
+               else
+                       dev->irq = mips_irq + 2;
+               if (dev->irq > 5)
+                       continue;
                switch (dev->id.coreid) {
                case SSB_DEV_USB11_HOST:
                        /* shouldn't need a separate irq line for non-4710, most of them have a proper
                         * external usb controller on the pci */
                        if ((bus->chip_id == 0x4710) && (irq <= 4)) {
                                set_irq(dev, irq++);
-                               break;
                        }
+                       break;
                        /* fallthrough */
                case SSB_DEV_PCI:
                case SSB_DEV_ETHERNET:
@@ -220,6 +283,8 @@ void ssb_mipscore_init(struct ssb_mipscore *mcore)
                        }
                }
        }
+       ssb_dprintk(KERN_INFO PFX "after irq reconfiguration\n");
+       dump_irq(bus);
 
        ssb_mips_serial_init(mcore);
        ssb_mips_flash_detect(mcore);
index 0e03408..42db410 100644 (file)
@@ -384,7 +384,8 @@ void handle_rx_irq(struct agnx_priv *priv)
 /*                     dump_ieee80211_hdr((struct ieee80211_hdr *)skb->data, "RX G"); */
                } else
                        agnx_bug("Unknown packets type");
-               ieee80211_rx_irqsafe(priv->hw, skb, &status);
+               memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status));
+               ieee80211_rx_irqsafe(priv->hw, skb);
                rx_desc_reinit(priv, i);
 
        } while (priv->rx.idx++);
index 3f303ae..7b8aa5e 100644 (file)
@@ -3134,7 +3134,7 @@ static int at76_tx(struct sk_buff *skb, struct net_device *netdev)
                       netdev->name, __func__);
                /* skip this packet */
                dev_kfree_skb(skb);
-               return 0;
+               return NETDEV_TX_OK;
        }
 
        if (priv->tx_urb->status == -EINPROGRESS) {
@@ -3142,14 +3142,14 @@ static int at76_tx(struct sk_buff *skb, struct net_device *netdev)
                       netdev->name, __func__);
                /* skip this packet */
                dev_kfree_skb(skb);
-               return 0;
+               return NETDEV_TX_OK;
        }
 
        if (skb->len < ETH_HLEN) {
                printk(KERN_ERR "%s: %s: skb too short (%d)\n",
                       netdev->name, __func__, skb->len);
                dev_kfree_skb(skb);
-               return 0;
+               return NETDEV_TX_OK;
        }
 
        at76_ledtrig_tx_activity();     /* tell ledtrigger we send a packet */
@@ -3173,7 +3173,7 @@ static int at76_tx(struct sk_buff *skb, struct net_device *netdev)
                               skb->data[ETH_HLEN + 1],
                               skb->data[ETH_HLEN + 2]);
                        dev_kfree_skb(skb);
-                       return 0;
+                       return NETDEV_TX_OK;
                }
        } else {
                /* add RFC 1042 header in front */
index fad25b7..8472418 100644 (file)
@@ -846,10 +846,9 @@ static dst_command_func dst_commands[] = {
 /*
  * Configuration parser.
  */
-static void cn_dst_callback(void *data)
+static void cn_dst_callback(struct cn_msg *msg)
 {
        struct dst_ctl *ctl;
-       struct cn_msg *msg = data;
        int err;
        struct dst_ctl_ack ack;
        struct dst_node *n = NULL, *tmp;
index 077724a..7b7cce1 100644 (file)
@@ -223,7 +223,7 @@ static int VEthXmit(struct sk_buff *pSkb_p, struct net_device *pNetDevice_p)
        }
 
       Exit:
-       return 0;
+       return NETDEV_TX_OK;
 
 }
 
index 540cbbb..7cd87ca 100644 (file)
@@ -659,7 +659,7 @@ int usbdrv_xmit_frame(struct sk_buff *skb, struct net_device *dev)
         netif_stop_queue(dev);
     }
 
-    return 0;
+    return NETDEV_TX_OK;
 }
 
 
@@ -796,13 +796,13 @@ int zfLnxVapXmitFrame(struct sk_buff *skb, struct net_device *dev)
     if (vapId >= ZM_VAP_PORT_NUMBER)
     {
         dev_kfree_skb_irq(skb);
-        return 0;
+        return NETDEV_TX_OK;
     }
 #if 1
     if (vap[vapId].openFlag == 0)
     {
         dev_kfree_skb_irq(skb);
-        return 0;
+        return NETDEV_TX_OK;
     }
 #endif
 
@@ -819,7 +819,7 @@ int zfLnxVapXmitFrame(struct sk_buff *skb, struct net_device *dev)
         netif_stop_queue(dev);
     }
 
-    return 0;
+    return NETDEV_TX_OK;
 }
 
 static const struct net_device_ops vap_netdev_ops = {
index 5db0004..89a6b92 100644 (file)
@@ -156,10 +156,7 @@ void zfLnxRecvEth(zdev_t* dev, zbuf_t* buf, u16_t port)
     switch(netif_rx(buf))
 #endif
     {
-    case NET_RX_BAD:
     case NET_RX_DROP:
-    case NET_RX_CN_MOD:
-    case NET_RX_CN_HIGH:
         break;
     default:
             macp->drv_stats.net_stats.rx_packets++;
index f298b9b..35c59d5 100644 (file)
@@ -862,7 +862,7 @@ int rt28xx_packet_xmit(struct sk_buff *skb)
 {
        struct net_device *net_dev = skb->dev;
        PRTMP_ADAPTER pAd = net_dev->ml_priv;
-       int status = 0;
+       int status = NETDEV_TX_OK;
        PNDIS_PACKET pPacket = (PNDIS_PACKET) skb;
 
        {
@@ -892,7 +892,7 @@ int rt28xx_packet_xmit(struct sk_buff *skb)
 
        STASendPackets((NDIS_HANDLE)pAd, (PPNDIS_PACKET) &pPacket, 1);
 
-       status = 0;
+       status = NETDEV_TX_OK;
 done:
 
        return status;
@@ -923,7 +923,7 @@ INT rt28xx_send_packets(
        if (!(net_dev->flags & IFF_UP))
        {
                RELEASE_NDIS_PACKET(pAd, (PNDIS_PACKET)skb_p, NDIS_STATUS_FAILURE);
-               return 0;
+               return NETDEV_TX_OK;
        }
 
        NdisZeroMemory((PUCHAR)&skb_p->cb[CB_OFF], 15);
index 1294e05..1b77460 100644 (file)
@@ -802,13 +802,13 @@ int ieee80211_xmit(struct sk_buff *skb,
                        if ((*ieee->hard_start_xmit)(txb, dev) == 0) {
                                stats->tx_packets++;
                                stats->tx_bytes += txb->payload_size;
-                               return 0;
+                               return NETDEV_TX_OK;
                        }
                        ieee80211_txb_free(txb);
                }
        }
 
-       return 0;
+       return NETDEV_TX_OK;
 
  failed:
        spin_unlock_irqrestore(&ieee->lock, flags);
index 7e2feca..26a5911 100644 (file)
@@ -3040,7 +3040,7 @@ int rtl8180_hard_start_xmit(struct sk_buff *skb,struct net_device *dev)
                spin_unlock_irqrestore(&priv->tx_lock,flags);
 
                dev_kfree_skb_any(skb);
-               return 0;
+               return NETDEV_TX_OK;
        }
 
        rtl8180_tx(dev, skb->data, skb->len, priority,
@@ -3051,7 +3051,7 @@ int rtl8180_hard_start_xmit(struct sk_buff *skb,struct net_device *dev)
        spin_unlock_irqrestore(&priv->tx_lock,flags);
 
        dev_kfree_skb_any(skb);
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 // longpre 144+48 shortpre 72+24
index ed47db5..b01a282 100644 (file)
@@ -845,7 +845,7 @@ static int slic_xmit_start(struct sk_buff *skb, struct net_device *dev)
                                 hcmd->paddrh, DONT_FLUSH);
        }
 xmit_done:
-       return 0;
+       return NETDEV_TX_OK;
 xmit_fail:
        slic_xmit_fail(adapter, skb, offloadcmd, skbtype, status);
        goto xmit_done;
index cfdaac9..52744fa 100644 (file)
@@ -1429,7 +1429,8 @@ static int stlc45xx_rx_data(struct stlc45xx *stlc, struct sk_buff *skb)
        stlc45xx_debug(DEBUG_RX, "rx data 0x%p %d B", skb->data, skb->len);
        stlc45xx_dump(DEBUG_RX_CONTENT, skb->data, skb->len);
 
-       ieee80211_rx(stlc->hw, skb, &status);
+       memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status));
+       ieee80211_rx(stlc->hw, skb);
 
        return 0;
 }
index 3e8cf08..b905e7b 100644 (file)
@@ -40,7 +40,8 @@ static void packet_came(struct ieee80211_hw *hw, char *pRxBufferAddress, int Pac
        rx_status.phymode = MODE_IEEE80211B;
 */
 
-       ieee80211_rx_irqsafe(hw, skb, &rx_status);
+       memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status));
+       ieee80211_rx_irqsafe(hw, skb);
 }
 
 static void Wb35Rx_adjust(PDESCRIPTOR pRxDes)
index 90f499e..c273c03 100644 (file)
@@ -354,7 +354,7 @@ static int p80211knetdev_hard_start_xmit(struct sk_buff *skb,
        p80211_metawep_t p80211_wep;
 
        if (skb == NULL)
-               return 0;
+               return NETDEV_TX_OK;
 
        if (wlandev->state != WLAN_DEVICE_OPEN) {
                result = 1;
index 38bfdb0..3f10459 100644 (file)
@@ -550,7 +550,7 @@ static void acm_waker(struct work_struct *waker)
 static int acm_tty_open(struct tty_struct *tty, struct file *filp)
 {
        struct acm *acm;
-       int rv = -EINVAL;
+       int rv = -ENODEV;
        int i;
        dbg("Entering acm_tty_open.");
 
@@ -677,7 +677,7 @@ static void acm_tty_close(struct tty_struct *tty, struct file *filp)
 
        /* Perform the closing process and see if we need to do the hardware
           shutdown */
-       if (tty_port_close_start(&acm->port, tty, filp) == 0)
+       if (!acm || tty_port_close_start(&acm->port, tty, filp) == 0)
                return;
        acm_port_down(acm, 0);
        tty_port_close_end(&acm->port, tty);
index 96fb118..d17f108 100644 (file)
@@ -256,7 +256,7 @@ out:
                dev_kfree_skb(skb);
                dev->stats.tx_dropped++;
        }
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 static int pn_net_mtu(struct net_device *dev, int new_mtu)
index 016f63b..aac69b5 100644 (file)
@@ -487,7 +487,7 @@ static int eth_start_xmit(struct sk_buff *skb, struct net_device *net)
 
        if (!in) {
                dev_kfree_skb_any(skb);
-               return 0;
+               return NETDEV_TX_OK;
        }
 
        /* apply outgoing CDC or RNDIS filters */
@@ -506,7 +506,7 @@ static int eth_start_xmit(struct sk_buff *skb, struct net_device *net)
                                type = USB_CDC_PACKET_TYPE_ALL_MULTICAST;
                        if (!(cdc_filter & type)) {
                                dev_kfree_skb_any(skb);
-                               return 0;
+                               return NETDEV_TX_OK;
                        }
                }
                /* ignores USB_CDC_PACKET_TYPE_DIRECTED */
@@ -586,7 +586,7 @@ drop:
                list_add(&req->list, &dev->tx_reqs);
                spin_unlock_irqrestore(&dev->req_lock, flags);
        }
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 /*-------------------------------------------------------------------------*/
index d595aa5..a842164 100644 (file)
@@ -333,6 +333,9 @@ static void serial_close(struct tty_struct *tty, struct file *filp)
 {
        struct usb_serial_port *port = tty->driver_data;
 
+       if (!port)
+               return;
+
        dbg("%s - port %d", __func__, port->number);
 
 
index d6d65ef..8afcf08 100644 (file)
@@ -616,6 +616,8 @@ config FB_STI
        select FB_CFB_FILLRECT
        select FB_CFB_COPYAREA
        select FB_CFB_IMAGEBLIT
+       select STI_CONSOLE
+       select VT
        default y
        ---help---
          STI refers to the HP "Standard Text Interface" which is a set of
index 018850c..497ff8a 100644 (file)
@@ -2414,7 +2414,10 @@ static int atafb_get_fix(struct fb_fix_screeninfo *fix, struct fb_info *info)
        if (err)
                return err;
        memset(fix, 0, sizeof(struct fb_fix_screeninfo));
-       return fbhw->encode_fix(fix, &par);
+       mutex_lock(&info->mm_lock);
+       err = fbhw->encode_fix(fix, &par);
+       mutex_unlock(&info->mm_lock);
+       return err;
 }
 
 static int atafb_get_var(struct fb_var_screeninfo *var, struct fb_info *info)
@@ -2743,7 +2746,9 @@ static int atafb_set_par(struct fb_info *info)
 
        /* Decode wanted screen parameters */
        fbhw->decode_var(&info->var, par);
+       mutex_lock(&info->mm_lock);
        fbhw->encode_fix(&info->fix, par);
+       mutex_unlock(&info->mm_lock);
 
        /* Set new videomode */
        ata_set_par(par);
index 5afd644..cb88394 100644 (file)
@@ -270,7 +270,9 @@ static int atmel_lcdfb_alloc_video_memory(struct atmel_lcdfb_info *sinfo)
 
        smem_len = (var->xres_virtual * var->yres_virtual
                    * ((var->bits_per_pixel + 7) / 8));
+       mutex_lock(&info->mm_lock);
        info->fix.smem_len = max(smem_len, sinfo->smem_len);
+       mutex_unlock(&info->mm_lock);
 
        info->screen_base = dma_alloc_writecombine(info->device, info->fix.smem_len,
                                        (dma_addr_t *)&info->fix.smem_start, GFP_KERNEL);
index 7691e73..1f39a62 100644 (file)
@@ -187,6 +187,8 @@ struct atyfb_par {
        int mtrr_reg;
 #endif
        u32 mem_cntl;
+       struct crtc saved_crtc;
+       union aty_pll saved_pll;
 };
 
     /*
@@ -217,6 +219,7 @@ struct atyfb_par {
 #define M64F_XL_DLL            0x00080000
 #define M64F_MFB_FORCE_4       0x00100000
 #define M64F_HW_TRIPLE         0x00200000
+#define M64F_XL_MEM            0x00400000
     /*
      *  Register access
      */
index 1207c20..63d3739 100644 (file)
@@ -66,6 +66,8 @@
 #include <linux/spinlock.h>
 #include <linux/wait.h>
 #include <linux/backlight.h>
+#include <linux/reboot.h>
+#include <linux/dmi.h>
 
 #include <asm/io.h>
 #include <linux/uaccess.h>
@@ -249,8 +251,6 @@ static int aty_init(struct fb_info *info);
 static int store_video_par(char *videopar, unsigned char m64_num);
 #endif
 
-static struct crtc saved_crtc;
-static union aty_pll saved_pll;
 static void aty_get_crtc(const struct atyfb_par *par, struct crtc *crtc);
 
 static void aty_set_crtc(const struct atyfb_par *par, const struct crtc *crtc);
@@ -261,6 +261,8 @@ static void set_off_pitch(struct atyfb_par *par, const struct fb_info *info);
 static int read_aty_sense(const struct atyfb_par *par);
 #endif
 
+static DEFINE_MUTEX(reboot_lock);
+static struct fb_info *reboot_info;
 
     /*
      *  Interface used by the world
@@ -361,8 +363,8 @@ static unsigned long phys_guiregbase[FB_MAX] __devinitdata = { 0, };
 #define ATI_CHIP_264GTPRO  (ATI_MODERN_SET | M64F_SDRAM_MAGIC_PLL | M64F_HW_TRIPLE | M64F_FIFO_32 | M64F_RESET_3D)
 #define ATI_CHIP_264LTPRO  (ATI_MODERN_SET | M64F_HW_TRIPLE | M64F_FIFO_32 | M64F_RESET_3D)
 
-#define ATI_CHIP_264XL     (ATI_MODERN_SET | M64F_HW_TRIPLE | M64F_FIFO_32 | M64F_RESET_3D | M64F_XL_DLL | M64F_MFB_FORCE_4)
-#define ATI_CHIP_MOBILITY  (ATI_MODERN_SET | M64F_HW_TRIPLE | M64F_FIFO_32 | M64F_RESET_3D | M64F_XL_DLL | M64F_MFB_FORCE_4 | M64F_MOBIL_BUS)
+#define ATI_CHIP_264XL     (ATI_MODERN_SET | M64F_HW_TRIPLE | M64F_FIFO_32 | M64F_RESET_3D | M64F_XL_DLL | M64F_MFB_FORCE_4 | M64F_XL_MEM)
+#define ATI_CHIP_MOBILITY  (ATI_MODERN_SET | M64F_HW_TRIPLE | M64F_FIFO_32 | M64F_RESET_3D | M64F_XL_DLL | M64F_MFB_FORCE_4 | M64F_XL_MEM | M64F_MOBIL_BUS)
 
 static struct {
        u16 pci_id;
@@ -539,6 +541,7 @@ static char ram_edo[] __devinitdata = "EDO";
 static char ram_sdram[] __devinitdata = "SDRAM (1:1)";
 static char ram_sgram[] __devinitdata = "SGRAM (1:1)";
 static char ram_sdram32[] __devinitdata = "SDRAM (2:1) (32-bit)";
+static char ram_wram[] __devinitdata = "WRAM";
 static char ram_off[] __devinitdata = "OFF";
 #endif /* CONFIG_FB_ATY_CT */
 
@@ -553,6 +556,10 @@ static char *aty_gx_ram[8] __devinitdata = {
 #ifdef CONFIG_FB_ATY_CT
 static char *aty_ct_ram[8] __devinitdata = {
        ram_off, ram_dram, ram_edo, ram_edo,
+       ram_sdram, ram_sgram, ram_wram, ram_resv
+};
+static char *aty_xl_ram[8] __devinitdata = {
+       ram_off, ram_dram, ram_edo, ram_edo,
        ram_sdram, ram_sgram, ram_sdram32, ram_resv
 };
 #endif /* CONFIG_FB_ATY_CT */
@@ -760,6 +767,17 @@ static void aty_set_crtc(const struct atyfb_par *par, const struct crtc *crtc)
 #endif /* CONFIG_FB_ATY_GENERIC_LCD */
 }
 
+static u32 calc_line_length(struct atyfb_par *par, u32 vxres, u32 bpp)
+{
+       u32 line_length = vxres * bpp / 8;
+
+       if (par->ram_type == SGRAM ||
+           (!M64_HAS(XL_MEM) && par->ram_type == WRAM))
+               line_length = (line_length + 63) & ~63;
+
+       return line_length;
+}
+
 static int aty_var_to_crtc(const struct fb_info *info,
        const struct fb_var_screeninfo *var, struct crtc *crtc)
 {
@@ -769,13 +787,14 @@ static int aty_var_to_crtc(const struct fb_info *info,
        u32 h_total, h_disp, h_sync_strt, h_sync_end, h_sync_dly, h_sync_wid, h_sync_pol;
        u32 v_total, v_disp, v_sync_strt, v_sync_end, v_sync_wid, v_sync_pol, c_sync;
        u32 pix_width, dp_pix_width, dp_chain_mask;
+       u32 line_length;
 
        /* input */
-       xres = var->xres;
+       xres = (var->xres + 7) & ~7;
        yres = var->yres;
-       vxres = var->xres_virtual;
+       vxres = (var->xres_virtual + 7) & ~7;
        vyres = var->yres_virtual;
-       xoffset = var->xoffset;
+       xoffset = (var->xoffset + 7) & ~7;
        yoffset = var->yoffset;
        bpp = var->bits_per_pixel;
        if (bpp == 16)
@@ -827,7 +846,9 @@ static int aty_var_to_crtc(const struct fb_info *info,
        } else
                FAIL("invalid bpp");
 
-       if (vxres * vyres * bpp / 8 > info->fix.smem_len)
+       line_length = calc_line_length(par, vxres, bpp);
+
+       if (vyres * line_length > info->fix.smem_len)
                FAIL("not enough video RAM");
 
        h_sync_pol = sync & FB_SYNC_HOR_HIGH_ACT ? 0 : 1;
@@ -969,7 +990,9 @@ static int aty_var_to_crtc(const struct fb_info *info,
        crtc->xoffset = xoffset;
        crtc->yoffset = yoffset;
        crtc->bpp = bpp;
-       crtc->off_pitch = ((yoffset*vxres+xoffset)*bpp/64) | (vxres<<19);
+       crtc->off_pitch =
+               ((yoffset * line_length + xoffset * bpp / 8) / 8) |
+               ((line_length / bpp) << 22);
        crtc->vline_crnt_vline = 0;
 
        crtc->h_tot_disp = h_total | (h_disp<<16);
@@ -1394,7 +1417,9 @@ static int atyfb_set_par(struct fb_info *info)
        }
        aty_st_8(DAC_MASK, 0xff, par);
 
-       info->fix.line_length = var->xres_virtual * var->bits_per_pixel/8;
+       info->fix.line_length = calc_line_length(par, var->xres_virtual,
+                                                var->bits_per_pixel);
+
        info->fix.visual = var->bits_per_pixel <= 8 ?
                FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_DIRECTCOLOR;
 
@@ -1505,10 +1530,12 @@ static void set_off_pitch(struct atyfb_par *par, const struct fb_info *info)
 {
        u32 xoffset = info->var.xoffset;
        u32 yoffset = info->var.yoffset;
-       u32 vxres = par->crtc.vxres;
+       u32 line_length = info->fix.line_length;
        u32 bpp = info->var.bits_per_pixel;
 
-       par->crtc.off_pitch = ((yoffset * vxres + xoffset) * bpp / 64) | (vxres << 19);
+       par->crtc.off_pitch =
+               ((yoffset * line_length + xoffset * bpp / 8) / 8) |
+               ((line_length / bpp) << 22);
 }
 
 
@@ -2201,7 +2228,7 @@ static void __devinit aty_calc_mem_refresh(struct atyfb_par *par, int xclk)
        const int *refresh_tbl;
        int i, size;
 
-       if (IS_XL(par->pci_id) || IS_MOBILITY(par->pci_id)) {
+       if (M64_HAS(XL_MEM)) {
                refresh_tbl = ragexl_tbl;
                size = ARRAY_SIZE(ragexl_tbl);
        } else {
@@ -2335,7 +2362,10 @@ static int __devinit aty_init(struct fb_info *info)
                par->pll_ops = &aty_pll_ct;
                par->bus_type = PCI;
                par->ram_type = (aty_ld_le32(CNFG_STAT0, par) & 0x07);
-               ramname = aty_ct_ram[par->ram_type];
+               if (M64_HAS(XL_MEM))
+                       ramname = aty_xl_ram[par->ram_type];
+               else
+                       ramname = aty_ct_ram[par->ram_type];
                /* for many chips, the mclk is 67 MHz for SDRAM, 63 MHz otherwise */
                if (par->pll_limits.mclk == 67 && par->ram_type < SDRAM)
                        par->pll_limits.mclk = 63;
@@ -2390,9 +2420,9 @@ static int __devinit aty_init(struct fb_info *info)
 #endif /* CONFIG_FB_ATY_CT */
 
        /* save previous video mode */
-       aty_get_crtc(par, &saved_crtc);
+       aty_get_crtc(par, &par->saved_crtc);
        if(par->pll_ops->get_pll)
-               par->pll_ops->get_pll(info, &saved_pll);
+               par->pll_ops->get_pll(info, &par->saved_pll);
 
        par->mem_cntl = aty_ld_le32(MEM_CNTL, par);
        gtb_memsize = M64_HAS(GTB_DSP);
@@ -2667,8 +2697,8 @@ static int __devinit aty_init(struct fb_info *info)
 
 aty_init_exit:
        /* restore video mode */
-       aty_set_crtc(par, &saved_crtc);
-       par->pll_ops->set_pll(info, &saved_pll);
+       aty_set_crtc(par, &par->saved_crtc);
+       par->pll_ops->set_pll(info, &par->saved_pll);
 
 #ifdef CONFIG_MTRR
        if (par->mtrr_reg >= 0) {
@@ -3502,6 +3532,11 @@ static int __devinit atyfb_pci_probe(struct pci_dev *pdev, const struct pci_devi
        par->mmap_map[1].prot_flag = _PAGE_E;
 #endif /* __sparc__ */
 
+       mutex_lock(&reboot_lock);
+       if (!reboot_info)
+               reboot_info = info;
+       mutex_unlock(&reboot_lock);
+
        return 0;
 
 err_release_io:
@@ -3614,8 +3649,8 @@ static void __devexit atyfb_remove(struct fb_info *info)
        struct atyfb_par *par = (struct atyfb_par *) info->par;
 
        /* restore video mode */
-       aty_set_crtc(par, &saved_crtc);
-       par->pll_ops->set_pll(info, &saved_pll);
+       aty_set_crtc(par, &par->saved_crtc);
+       par->pll_ops->set_pll(info, &par->saved_pll);
 
        unregister_framebuffer(info);
 
@@ -3661,6 +3696,11 @@ static void __devexit atyfb_pci_remove(struct pci_dev *pdev)
 {
        struct fb_info *info = pci_get_drvdata(pdev);
 
+       mutex_lock(&reboot_lock);
+       if (reboot_info == info)
+               reboot_info = NULL;
+       mutex_unlock(&reboot_lock);
+
        atyfb_remove(info);
 }
 
@@ -3808,6 +3848,56 @@ static int __init atyfb_setup(char *options)
 }
 #endif  /*  MODULE  */
 
+static int atyfb_reboot_notify(struct notifier_block *nb,
+                              unsigned long code, void *unused)
+{
+       struct atyfb_par *par;
+
+       if (code != SYS_RESTART)
+               return NOTIFY_DONE;
+
+       mutex_lock(&reboot_lock);
+
+       if (!reboot_info)
+               goto out;
+
+       if (!lock_fb_info(reboot_info))
+               goto out;
+
+       par = reboot_info->par;
+
+       /*
+        * HP OmniBook 500's BIOS doesn't like the state of the
+        * hardware after atyfb has been used. Restore the hardware
+        * to the original state to allow successful reboots.
+        */
+       aty_set_crtc(par, &par->saved_crtc);
+       par->pll_ops->set_pll(reboot_info, &par->saved_pll);
+
+       unlock_fb_info(reboot_info);
+ out:
+       mutex_unlock(&reboot_lock);
+
+       return NOTIFY_DONE;
+}
+
+static struct notifier_block atyfb_reboot_notifier = {
+       .notifier_call = atyfb_reboot_notify,
+};
+
+static const struct dmi_system_id atyfb_reboot_ids[] = {
+       {
+               .ident = "HP OmniBook 500",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "HP OmniBook PC"),
+                       DMI_MATCH(DMI_PRODUCT_VERSION, "HP OmniBook 500 FA"),
+               },
+       },
+
+       { }
+};
+
 static int __init atyfb_init(void)
 {
     int err1 = 1, err2 = 1;
@@ -3826,11 +3916,20 @@ static int __init atyfb_init(void)
     err2 = atyfb_atari_probe();
 #endif
 
-    return (err1 && err2) ? -ENODEV : 0;
+    if (err1 && err2)
+       return -ENODEV;
+
+    if (dmi_check_system(atyfb_reboot_ids))
+       register_reboot_notifier(&atyfb_reboot_notifier);
+
+    return 0;
 }
 
 static void __exit atyfb_exit(void)
 {
+       if (dmi_check_system(atyfb_reboot_ids))
+               unregister_reboot_notifier(&atyfb_reboot_notifier);
+
 #ifdef CONFIG_PCI
        pci_unregister_driver(&atyfb_driver);
 #endif
index 0cc9724..51fcc0a 100644 (file)
@@ -63,14 +63,17 @@ static void reset_GTC_3D_engine(const struct atyfb_par *par)
 void aty_init_engine(struct atyfb_par *par, struct fb_info *info)
 {
        u32 pitch_value;
+       u32 vxres;
 
        /* determine modal information from global mode structure */
-       pitch_value = info->var.xres_virtual;
+       pitch_value = info->fix.line_length / (info->var.bits_per_pixel / 8);
+       vxres = info->var.xres_virtual;
 
        if (info->var.bits_per_pixel == 24) {
                /* In 24 bpp, the engine is in 8 bpp - this requires that all */
                /* horizontal coordinates and widths must be adjusted */
                pitch_value *= 3;
+               vxres *= 3;
        }
 
        /* On GTC (RagePro), we need to reset the 3D engine before */
@@ -133,7 +136,7 @@ void aty_init_engine(struct atyfb_par *par, struct fb_info *info)
        aty_st_le32(SC_LEFT, 0, par);
        aty_st_le32(SC_TOP, 0, par);
        aty_st_le32(SC_BOTTOM, par->crtc.vyres - 1, par);
-       aty_st_le32(SC_RIGHT, pitch_value - 1, par);
+       aty_st_le32(SC_RIGHT, vxres - 1, par);
 
        /* set background color to minimum value (usually BLACK) */
        aty_st_le32(DP_BKGD_CLR, 0, par);
index 1dae7f8..51422fc 100644 (file)
@@ -356,7 +356,7 @@ static int __devinit tdo24m_probe(struct spi_device *spi)
        lcd->power = FB_BLANK_POWERDOWN;
        lcd->mode = MODE_VGA;   /* default to VGA */
 
-       lcd->buf = kmalloc(TDO24M_SPI_BUFF_SIZE, sizeof(GFP_KERNEL));
+       lcd->buf = kmalloc(TDO24M_SPI_BUFF_SIZE, GFP_KERNEL);
        if (lcd->buf == NULL) {
                kfree(lcd);
                return -ENOMEM;
index 7bad24e..108b89e 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  Cobalt server LCD frame buffer driver.
  *
- *  Copyright (C) 2008  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *  Copyright (C) 2008  Yoichi Yuasa <yuasa@linux-mips.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
index f8a09bf..53ea056 100644 (file)
@@ -1310,8 +1310,6 @@ static long fb_compat_ioctl(struct file *file, unsigned int cmd,
 
 static int
 fb_mmap(struct file *file, struct vm_area_struct * vma)
-__acquires(&info->lock)
-__releases(&info->lock)
 {
        int fbidx = iminor(file->f_path.dentry->d_inode);
        struct fb_info *info = registered_fb[fbidx];
@@ -1325,16 +1323,14 @@ __releases(&info->lock)
        off = vma->vm_pgoff << PAGE_SHIFT;
        if (!fb)
                return -ENODEV;
+       mutex_lock(&info->mm_lock);
        if (fb->fb_mmap) {
                int res;
-               mutex_lock(&info->lock);
                res = fb->fb_mmap(info, vma);
-               mutex_unlock(&info->lock);
+               mutex_unlock(&info->mm_lock);
                return res;
        }
 
-       mutex_lock(&info->lock);
-
        /* frame buffer memory */
        start = info->fix.smem_start;
        len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.smem_len);
@@ -1342,13 +1338,13 @@ __releases(&info->lock)
                /* memory mapped io */
                off -= len;
                if (info->var.accel_flags) {
-                       mutex_unlock(&info->lock);
+                       mutex_unlock(&info->mm_lock);
                        return -EINVAL;
                }
                start = info->fix.mmio_start;
                len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.mmio_len);
        }
-       mutex_unlock(&info->lock);
+       mutex_unlock(&info->mm_lock);
        start &= PAGE_MASK;
        if ((vma->vm_end - vma->vm_start + off) > len)
                return -EINVAL;
@@ -1518,6 +1514,7 @@ register_framebuffer(struct fb_info *fb_info)
                        break;
        fb_info->node = i;
        mutex_init(&fb_info->lock);
+       mutex_init(&fb_info->mm_lock);
 
        fb_info->dev = device_create(fb_class, fb_info->device,
                                     MKDEV(FB_MAJOR, i), NULL, "fb%d", i);
index f153c58..0bf2190 100644 (file)
@@ -750,24 +750,26 @@ static void update_lcdc(struct fb_info *info)
 static int map_video_memory(struct fb_info *info)
 {
        phys_addr_t phys;
+       u32 smem_len = info->fix.line_length * info->var.yres_virtual;
 
        pr_debug("info->var.xres_virtual = %d\n", info->var.xres_virtual);
        pr_debug("info->var.yres_virtual = %d\n", info->var.yres_virtual);
        pr_debug("info->fix.line_length  = %d\n", info->fix.line_length);
+       pr_debug("MAP_VIDEO_MEMORY: smem_len = %u\n", smem_len);
 
-       info->fix.smem_len = info->fix.line_length * info->var.yres_virtual;
-       pr_debug("MAP_VIDEO_MEMORY: smem_len = %d\n", info->fix.smem_len);
-       info->screen_base = fsl_diu_alloc(info->fix.smem_len, &phys);
+       info->screen_base = fsl_diu_alloc(smem_len, &phys);
        if (info->screen_base == NULL) {
                printk(KERN_ERR "Unable to allocate fb memory\n");
                return -ENOMEM;
        }
+       mutex_lock(&info->mm_lock);
        info->fix.smem_start = (unsigned long) phys;
+       info->fix.smem_len = smem_len;
+       mutex_unlock(&info->mm_lock);
        info->screen_size = info->fix.smem_len;
 
        pr_debug("Allocated fb @ paddr=0x%08lx, size=%d.\n",
-                               info->fix.smem_start,
-               info->fix.smem_len);
+                info->fix.smem_start, info->fix.smem_len);
        pr_debug("screen base %p\n", info->screen_base);
 
        return 0;
@@ -776,9 +778,11 @@ static int map_video_memory(struct fb_info *info)
 static void unmap_video_memory(struct fb_info *info)
 {
        fsl_diu_free(info->screen_base, info->fix.smem_len);
+       mutex_lock(&info->mm_lock);
        info->screen_base = NULL;
        info->fix.smem_start = 0;
        info->fix.smem_len = 0;
+       mutex_unlock(&info->mm_lock);
 }
 
 /*
index 2e94019..7196067 100644 (file)
@@ -1090,8 +1090,10 @@ static int encode_fix(struct fb_fix_screeninfo *fix, struct fb_info *info)
        memset(fix, 0, sizeof(struct fb_fix_screeninfo));
 
        strcpy(fix->id, "I810");
+       mutex_lock(&info->mm_lock);
        fix->smem_start = par->fb.physical;
        fix->smem_len = par->fb.size;
+       mutex_unlock(&info->mm_lock);
        fix->type = FB_TYPE_PACKED_PIXELS;
        fix->type_aux = 0;
        fix->xpanstep = 8;
index 8e7a275..59c3a2e 100644 (file)
@@ -724,8 +724,10 @@ static void matroxfb_update_fix(WPMINFO2)
        struct fb_fix_screeninfo *fix = &ACCESS_FBINFO(fbcon).fix;
        DBG(__func__)
 
+       mutex_lock(&ACCESS_FBINFO(fbcon).mm_lock);
        fix->smem_start = ACCESS_FBINFO(video.base) + ACCESS_FBINFO(curr.ydstorg.bytes);
        fix->smem_len = ACCESS_FBINFO(video.len_usable) - ACCESS_FBINFO(curr.ydstorg.bytes);
+       mutex_unlock(&ACCESS_FBINFO(fbcon).mm_lock);
 }
 
 static int matroxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
@@ -2081,6 +2083,7 @@ static int matroxfb_probe(struct pci_dev* pdev, const struct pci_device_id* dumm
        spin_lock_init(&ACCESS_FBINFO(lock.accel));
        init_rwsem(&ACCESS_FBINFO(crtc2.lock));
        init_rwsem(&ACCESS_FBINFO(altout.lock));
+       mutex_init(&ACCESS_FBINFO(fbcon).mm_lock);
        ACCESS_FBINFO(irq_flags) = 0;
        init_waitqueue_head(&ACCESS_FBINFO(crtc1.vsync.wait));
        init_waitqueue_head(&ACCESS_FBINFO(crtc2.vsync.wait));
index 7ac4c5f..909e10a 100644 (file)
@@ -289,13 +289,16 @@ static int matroxfb_dh_release(struct fb_info* info, int user) {
 #undef m2info
 }
 
-static void matroxfb_dh_init_fix(struct matroxfb_dh_fb_info *m2info) {
+static void matroxfb_dh_init_fix(struct matroxfb_dh_fb_info *m2info)
+{
        struct fb_fix_screeninfo *fix = &m2info->fbcon.fix;
 
        strcpy(fix->id, "MATROX DH");
 
+       mutex_lock(&m2info->fbcon.mm_lock);
        fix->smem_start = m2info->video.base;
        fix->smem_len = m2info->video.len_usable;
+       mutex_unlock(&m2info->fbcon.mm_lock);
        fix->ypanstep = 1;
        fix->ywrapstep = 0;
        fix->xpanstep = 8;      /* TBD */
index b7af525..567fb94 100644 (file)
@@ -669,7 +669,7 @@ static uint32_t bpp_to_pixfmt(int bpp)
 }
 
 static int mx3fb_blank(int blank, struct fb_info *fbi);
-static int mx3fb_map_video_memory(struct fb_info *fbi);
+static int mx3fb_map_video_memory(struct fb_info *fbi, unsigned int mem_len);
 static int mx3fb_unmap_video_memory(struct fb_info *fbi);
 
 /**
@@ -742,8 +742,7 @@ static int mx3fb_set_par(struct fb_info *fbi)
                if (fbi->fix.smem_start)
                        mx3fb_unmap_video_memory(fbi);
 
-               fbi->fix.smem_len = mem_len;
-               if (mx3fb_map_video_memory(fbi) < 0) {
+               if (mx3fb_map_video_memory(fbi, mem_len) < 0) {
                        mutex_unlock(&mx3_fbi->mutex);
                        return -ENOMEM;
                }
@@ -1198,6 +1197,7 @@ static int mx3fb_resume(struct platform_device *pdev)
 /**
  * mx3fb_map_video_memory() - allocates the DRAM memory for the frame buffer.
  * @fbi:       framebuffer information pointer
+ * @mem_len:   length of mapped memory
  * @return:    Error code indicating success or failure
  *
  * This buffer is remapped into a non-cached, non-buffered, memory region to
@@ -1205,23 +1205,26 @@ static int mx3fb_resume(struct platform_device *pdev)
  * area is remapped, all virtual memory access to the video memory should occur
  * at the new region.
  */
-static int mx3fb_map_video_memory(struct fb_info *fbi)
+static int mx3fb_map_video_memory(struct fb_info *fbi, unsigned int mem_len)
 {
        int retval = 0;
        dma_addr_t addr;
 
        fbi->screen_base = dma_alloc_writecombine(fbi->device,
-                                                 fbi->fix.smem_len,
+                                                 mem_len,
                                                  &addr, GFP_DMA);
 
        if (!fbi->screen_base) {
                dev_err(fbi->device, "Cannot allocate %u bytes framebuffer memory\n",
-                       fbi->fix.smem_len);
+                       mem_len);
                retval = -EBUSY;
                goto err0;
        }
 
+       mutex_lock(&fbi->mm_lock);
        fbi->fix.smem_start = addr;
+       fbi->fix.smem_len = mem_len;
+       mutex_unlock(&fbi->mm_lock);
 
        dev_dbg(fbi->device, "allocated fb @ p=0x%08x, v=0x%p, size=%d.\n",
                (uint32_t) fbi->fix.smem_start, fbi->screen_base, fbi->fix.smem_len);
@@ -1251,8 +1254,10 @@ static int mx3fb_unmap_video_memory(struct fb_info *fbi)
                              fbi->screen_base, fbi->fix.smem_start);
 
        fbi->screen_base = 0;
+       mutex_lock(&fbi->mm_lock);
        fbi->fix.smem_start = 0;
        fbi->fix.smem_len = 0;
+       mutex_unlock(&fbi->mm_lock);
        return 0;
 }
 
index 060d72f..4ea99bf 100644 (file)
@@ -393,8 +393,10 @@ static void set_fb_fix(struct fb_info *fbi)
 
        rg = &plane->fbdev->mem_desc.region[plane->idx];
        fbi->screen_base        = rg->vaddr;
+       mutex_lock(&fbi->mm_lock);
        fix->smem_start         = rg->paddr;
        fix->smem_len           = rg->size;
+       mutex_unlock(&fbi->mm_lock);
 
        fix->type = FB_TYPE_PACKED_PIXELS;
        bpp = var->bits_per_pixel;
@@ -886,8 +888,10 @@ static int omapfb_setup_mem(struct fb_info *fbi, struct omapfb_mem_info *mi)
                                 * plane memory is dealloce'd, the other
                                 * screen parameters in var / fix are invalid.
                                 */
+                               mutex_lock(&fbi->mm_lock);
                                fbi->fix.smem_start = 0;
                                fbi->fix.smem_len = 0;
+                               mutex_unlock(&fbi->mm_lock);
                        }
                }
        }
index 03b3670..bacfabd 100644 (file)
@@ -141,7 +141,9 @@ static int platinumfb_set_par (struct fb_info *info)
                offset = 0x10;
 
        info->screen_base = pinfo->frame_buffer + init->fb_offset + offset;
+       mutex_lock(&info->mm_lock);
        info->fix.smem_start = (pinfo->frame_buffer_phys) + init->fb_offset + offset;
+       mutex_unlock(&info->mm_lock);
        info->fix.visual = (pinfo->cmode == CMODE_8) ?
                FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_DIRECTCOLOR;
        info->fix.line_length = vmode_attrs[pinfo->vmode-1].hres * (1<<pinfo->cmode)
index 0889d50..6506117 100644 (file)
@@ -815,8 +815,10 @@ static int overlayfb_map_video_memory(struct pxafb_layer *ofb)
        ofb->video_mem_phys = virt_to_phys(ofb->video_mem);
        ofb->video_mem_size = size;
 
+       mutex_lock(&ofb->fb.mm_lock);
        ofb->fb.fix.smem_start  = ofb->video_mem_phys;
        ofb->fb.fix.smem_len    = ofb->fb.fix.line_length * var->yres_virtual;
+       mutex_unlock(&ofb->fb.mm_lock);
        ofb->fb.screen_base     = ofb->video_mem;
        return 0;
 }
index 653bdfe..9f6d6e6 100644 (file)
@@ -120,18 +120,6 @@ static int sh7760_setcolreg (u_int regno,
        return 0;
 }
 
-static void encode_fix(struct fb_fix_screeninfo *fix, struct fb_info *info,
-                      unsigned long stride)
-{
-       memset(fix, 0, sizeof(struct fb_fix_screeninfo));
-       strcpy(fix->id, "sh7760-lcdc");
-
-       fix->smem_start = (unsigned long)info->screen_base;
-       fix->smem_len = info->screen_size;
-
-       fix->line_length = stride;
-}
-
 static int sh7760fb_get_color_info(struct device *dev,
                                   u16 lddfr, int *bpp, int *gray)
 {
@@ -334,7 +322,8 @@ static int sh7760fb_set_par(struct fb_info *info)
 
        iowrite32(ldsarl, par->base + LDSARL);  /* mem for lower half of DSTN */
 
-       encode_fix(&info->fix, info, stride);
+       info->fix.line_length = stride;
+
        sh7760fb_check_var(&info->var, info);
 
        sh7760fb_blank(FB_BLANK_UNBLANK, info); /* panel on! */
@@ -435,6 +424,8 @@ static int sh7760fb_alloc_mem(struct fb_info *info)
 
        info->screen_base = fbmem;
        info->screen_size = vram;
+       info->fix.smem_start = (unsigned long)info->screen_base;
+       info->fix.smem_len = info->screen_size;
 
        return 0;
 }
@@ -520,6 +511,8 @@ static int __devinit sh7760fb_probe(struct platform_device *pdev)
        info->var.transp.length = 0;
        info->var.transp.msb_right = 0;
 
+       strcpy(info->fix.id, "sh7760-lcdc");
+
        /* set the DON2 bit now, before cmap allocation, as it will randomize
         * palette memory.
         */
index f10d2fb..da983b7 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/platform_device.h>
 #include <linux/dma-mapping.h>
 #include <linux/interrupt.h>
+#include <linux/vmalloc.h>
 #include <video/sh_mobile_lcdc.h>
 #include <asm/atomic.h>
 
@@ -33,6 +34,7 @@ struct sh_mobile_lcdc_chan {
        struct fb_info info;
        dma_addr_t dma_handle;
        struct fb_deferred_io defio;
+       struct scatterlist *sglist;
        unsigned long frame_end;
        wait_queue_head_t frame_end_wait;
 };
@@ -206,16 +208,38 @@ static void sh_mobile_lcdc_clk_on(struct sh_mobile_lcdc_priv *priv) {}
 static void sh_mobile_lcdc_clk_off(struct sh_mobile_lcdc_priv *priv) {}
 #endif
 
+static int sh_mobile_lcdc_sginit(struct fb_info *info,
+                                 struct list_head *pagelist)
+{
+       struct sh_mobile_lcdc_chan *ch = info->par;
+       unsigned int nr_pages_max = info->fix.smem_len >> PAGE_SHIFT;
+       struct page *page;
+       int nr_pages = 0;
+
+       sg_init_table(ch->sglist, nr_pages_max);
+
+       list_for_each_entry(page, pagelist, lru)
+               sg_set_page(&ch->sglist[nr_pages++], page, PAGE_SIZE, 0);
+
+       return nr_pages;
+}
+
 static void sh_mobile_lcdc_deferred_io(struct fb_info *info,
                                       struct list_head *pagelist)
 {
        struct sh_mobile_lcdc_chan *ch = info->par;
+       unsigned int nr_pages;
 
        /* enable clocks before accessing hardware */
        sh_mobile_lcdc_clk_on(ch->lcdc);
 
+       nr_pages = sh_mobile_lcdc_sginit(info, pagelist);
+       dma_map_sg(info->dev, ch->sglist, nr_pages, DMA_TO_DEVICE);
+
        /* trigger panel update */
        lcdc_write_chan(ch, LDSM2R, 1);
+
+       dma_unmap_sg(info->dev, ch->sglist, nr_pages, DMA_TO_DEVICE);
 }
 
 static void sh_mobile_lcdc_deferred_io_touch(struct fb_info *info)
@@ -846,21 +870,31 @@ static int __init sh_mobile_lcdc_probe(struct platform_device *pdev)
        }
 
        for (i = 0; i < j; i++) {
-               error = register_framebuffer(&priv->ch[i].info);
+               struct sh_mobile_lcdc_chan *ch = priv->ch + i;
+
+               info = &ch->info;
+
+               if (info->fbdefio) {
+                       priv->ch->sglist = vmalloc(sizeof(struct scatterlist) *
+                                       info->fix.smem_len >> PAGE_SHIFT);
+                       if (!priv->ch->sglist) {
+                               dev_err(&pdev->dev, "cannot allocate sglist\n");
+                               goto err1;
+                       }
+               }
+
+               error = register_framebuffer(info);
                if (error < 0)
                        goto err1;
-       }
 
-       for (i = 0; i < j; i++) {
-               info = &priv->ch[i].info;
                dev_info(info->dev,
                         "registered %s/%s as %dx%d %dbpp.\n",
                         pdev->name,
-                        (priv->ch[i].cfg.chan == LCDC_CHAN_MAINLCD) ?
+                        (ch->cfg.chan == LCDC_CHAN_MAINLCD) ?
                         "mainlcd" : "sublcd",
-                        (int) priv->ch[i].cfg.lcd_cfg.xres,
-                        (int) priv->ch[i].cfg.lcd_cfg.yres,
-                        priv->ch[i].cfg.bpp);
+                        (int) ch->cfg.lcd_cfg.xres,
+                        (int) ch->cfg.lcd_cfg.yres,
+                        ch->cfg.bpp);
 
                /* deferred io mode: disable clock to save power */
                if (info->fbdefio)
@@ -892,6 +926,9 @@ static int sh_mobile_lcdc_remove(struct platform_device *pdev)
                if (!info->device)
                        continue;
 
+               if (priv->ch[i].sglist)
+                       vfree(priv->ch[i].sglist);
+
                dma_free_coherent(&pdev->dev, info->fix.smem_len,
                                  info->screen_base, priv->ch[i].dma_handle);
                fb_dealloc_cmap(&info->cmap);
index 7072d19..fd33455 100644 (file)
@@ -1847,8 +1847,10 @@ sisfb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info)
 
        strcpy(fix->id, ivideo->myid);
 
+       mutex_lock(&info->mm_lock);
        fix->smem_start  = ivideo->video_base + ivideo->video_offset;
        fix->smem_len    = ivideo->sisfb_mem;
+       mutex_unlock(&info->mm_lock);
        fix->type        = FB_TYPE_PACKED_PIXELS;
        fix->type_aux    = 0;
        fix->visual      = (ivideo->video_bpp == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
index eb5d73a..16d4f4c 100644 (file)
@@ -145,7 +145,7 @@ static inline void sm501fb_sync_regs(struct sm501fb_info *info)
 #define SM501_MEMF_ACCEL               (8)
 
 static int sm501_alloc_mem(struct sm501fb_info *inf, struct sm501_mem *mem,
-                          unsigned int why, size_t size)
+                          unsigned int why, size_t size, u32 smem_len)
 {
        struct sm501fb_par *par;
        struct fb_info *fbi;
@@ -172,7 +172,7 @@ static int sm501_alloc_mem(struct sm501fb_info *inf, struct sm501_mem *mem,
                if (ptr > 0)
                        ptr &= ~(PAGE_SIZE - 1);
 
-               if (fbi && ptr < fbi->fix.smem_len)
+               if (fbi && ptr < smem_len)
                        return -ENOMEM;
 
                break;
@@ -197,7 +197,7 @@ static int sm501_alloc_mem(struct sm501fb_info *inf, struct sm501_mem *mem,
 
        case SM501_MEMF_ACCEL:
                fbi = inf->fb[HEAD_CRT];
-               ptr = fbi ? fbi->fix.smem_len : 0;
+               ptr = fbi ? smem_len : 0;
 
                fbi = inf->fb[HEAD_PANEL];
                if (fbi) {
@@ -413,6 +413,7 @@ static int sm501fb_set_par_common(struct fb_info *info,
        unsigned int mem_type;
        unsigned int clock_type;
        unsigned int head_addr;
+       unsigned int smem_len;
 
        dev_dbg(fbi->dev, "%s: %dx%d, bpp = %d, virtual %dx%d\n",
                __func__, var->xres, var->yres, var->bits_per_pixel,
@@ -453,18 +454,20 @@ static int sm501fb_set_par_common(struct fb_info *info,
 
        /* allocate fb memory within 501 */
        info->fix.line_length = (var->xres_virtual * var->bits_per_pixel)/8;
-       info->fix.smem_len    = info->fix.line_length * var->yres_virtual;
+       smem_len = info->fix.line_length * var->yres_virtual;
 
        dev_dbg(fbi->dev, "%s: line length = %u\n", __func__,
                info->fix.line_length);
 
-       if (sm501_alloc_mem(fbi, &par->screen, mem_type,
-                           info->fix.smem_len)) {
+       if (sm501_alloc_mem(fbi, &par->screen, mem_type, smem_len, smem_len)) {
                dev_err(fbi->dev, "no memory available\n");
                return -ENOMEM;
        }
 
+       mutex_lock(&info->mm_lock);
        info->fix.smem_start = fbi->fbmem_res->start + par->screen.sm_addr;
+       info->fix.smem_len   = smem_len;
+       mutex_unlock(&info->mm_lock);
 
        info->screen_base = fbi->fbmem + par->screen.sm_addr;
        info->screen_size = info->fix.smem_len;
@@ -637,7 +640,8 @@ static int sm501fb_set_par_crt(struct fb_info *info)
        if ((control & SM501_DC_CRT_CONTROL_SEL) == 0) {
                /* the head is displaying panel data... */
 
-               sm501_alloc_mem(fbi, &par->screen, SM501_MEMF_CRT, 0);
+               sm501_alloc_mem(fbi, &par->screen, SM501_MEMF_CRT, 0,
+                               info->fix.smem_len);
                goto out_update;
        }
 
@@ -1289,7 +1293,8 @@ static int sm501_init_cursor(struct fb_info *fbi, unsigned int reg_base)
 
        par->cursor_regs = info->regs + reg_base;
 
-       ret = sm501_alloc_mem(info, &par->cursor, SM501_MEMF_CURSOR, 1024);
+       ret = sm501_alloc_mem(info, &par->cursor, SM501_MEMF_CURSOR, 1024,
+                             fbi->fix.smem_len);
        if (ret < 0)
                return ret;
 
@@ -1619,6 +1624,8 @@ static int __devinit sm501fb_start_one(struct sm501fb_info *info,
        if (!fbi)
                return 0;
 
+       mutex_init(&info->fb[head]->mm_lock);
+
        ret = sm501fb_init_fb(info->fb[head], head, drvname);
        if (ret) {
                dev_err(info->dev, "cannot initialise fb %s\n", drvname);
index ca5b464..e98baf6 100644 (file)
@@ -67,9 +67,8 @@ static DEFINE_MUTEX(uvfb_lock);
  * find the kernel part of the task struct, copy the registers and
  * the buffer contents and then complete the task.
  */
-static void uvesafb_cn_callback(void *data)
+static void uvesafb_cn_callback(struct cn_msg *msg)
 {
-       struct cn_msg *msg = data;
        struct uvesafb_task *utask;
        struct uvesafb_ktask *task;
 
index d0674f1..8a141c2 100644 (file)
@@ -523,6 +523,7 @@ static int w100fb_set_par(struct fb_info *info)
                info->fix.ywrapstep = 0;
                info->fix.line_length = par->xres * BITS_PER_PIXEL / 8;
 
+               mutex_lock(&info->mm_lock);
                if ((par->xres*par->yres*BITS_PER_PIXEL/8) > (MEM_INT_SIZE+1)) {
                        par->extmem_active = 1;
                        info->fix.smem_len = par->mach->mem->size+1;
@@ -530,6 +531,7 @@ static int w100fb_set_par(struct fb_info *info)
                        par->extmem_active = 0;
                        info->fix.smem_len = MEM_INT_SIZE+1;
                }
+               mutex_unlock(&info->mm_lock);
 
                w100fb_activate_var(par);
        }
index fdf7285..52ccb3d 100644 (file)
@@ -306,9 +306,8 @@ static int w1_netlink_send_error(struct cn_msg *rcmsg, struct w1_netlink_msg *rm
        return error;
 }
 
-static void w1_cn_callback(void *data)
+static void w1_cn_callback(struct cn_msg *msg)
 {
-       struct cn_msg *msg = data;
        struct w1_netlink_msg *m = (struct w1_netlink_msg *)(msg + 1);
        struct w1_netlink_cmd *cmd;
        struct w1_slave *sl;
index a4fe7a3..3bde56b 100644 (file)
@@ -218,16 +218,14 @@ static void wdrtas_timer_keepalive(void)
  */
 static int wdrtas_get_temperature(void)
 {
-       long result;
+       int result;
        int temperature = 0;
 
-       result = rtas_call(wdrtas_token_get_sensor_state, 2, 2,
-                          (void *)__pa(&temperature),
-                          WDRTAS_THERMAL_SENSOR, 0);
+       result = rtas_get_sensor(WDRTAS_THERMAL_SENSOR, 0, &temperature);
 
        if (result < 0)
                printk(KERN_WARNING "wdrtas: reading the thermal sensor "
-                      "faild: %li\n", result);
+                      "failed: %i\n", result);
        else
                temperature = ((temperature * 9) / 5) + 32; /* fahrenheit */
 
index 621de8e..44313b2 100644 (file)
@@ -41,7 +41,10 @@ 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.4.0.bin
+                                  cxgb3/t3fw-7.4.0.bin \
+                                  cxgb3/ael2005_opt_edc.bin \
+                                  cxgb3/ael2005_twx_edc.bin \
+                                  cxgb3/ael2020_twx_edc.bin
 fw-shipped-$(CONFIG_DVB_AV7110) += av7110/bootcode.bin
 fw-shipped-$(CONFIG_DVB_TTUSB_BUDGET) += ttusb-budget/dspbootcode.bin
 fw-shipped-$(CONFIG_E100) += e100/d101m_ucode.bin e100/d101s_ucode.bin \
index 0f5649a..d9e3a94 100644 (file)
@@ -418,6 +418,23 @@ License: GPLv2 or OpenIB.org BSD license, no source visible
 
 --------------------------------------------------------------------------
 
+Driver: cxgb3 - Chelsio Terminator 3 1G/10G Ethernet adapter
+
+File: cxgb3/ael2005_opt_edc.bin.ihex
+File: cxgb3/ael2005_twx_edc.bin.ihex
+File: cxgb3/ael2020_twx_edc.bin.ihex
+
+Licence:
+ *     Copyright (c) 2007-2009 NetLogic Microsystems, Inc.
+ *
+ *     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: e100 -- Intel PRO/100 Ethernet NIC
 
 File: e100/d101m_ucode.bin
diff --git a/firmware/cxgb3/ael2005_opt_edc.bin.ihex b/firmware/cxgb3/ael2005_opt_edc.bin.ihex
new file mode 100644 (file)
index 0000000..c1d6e5d
--- /dev/null
@@ -0,0 +1,69 @@
+:10000000CC002FF4CC013CD4CC022015CC0331051C
+:10001000CC046524CC0527FFCC06300FCC072C8BF5
+:10002000CC08300BCC094009CC0A400ECC0B2F7207
+:10003000CC0C3002CC0D1002CC0E2172CC0F301241
+:10004000CC101002CC1125D2CC123012CC131002DD
+:10005000CC14D01ECC1527D2CC163012CC171002DF
+:10006000CC182004CC193C84CC1A6436CC1B200755
+:10007000CC1C3F87CC1D8676CC1E40B7CC1FA74634
+:10008000CC204047CC215673CC222982CC2330028D
+:10009000CC2413D2CC258BBDCC262862CC273012A1
+:1000A000CC281002CC292092CC2A3012CC2B100262
+:1000B000CC2C5CC3CC2D0314CC2E2942CC2F300287
+:1000C000CC301002CC31D019CC322032CC333012AB
+:1000D000CC341002CC352A04CC363C74CC37643591
+:1000E000CC382FA4CC393CD4CC3A6624CC3B5563D5
+:1000F000CC3C2D42CC3D3002CC3E13D2CC3F464DC1
+:10010000CC402862CC413012CC421002CC43203289
+:10011000CC443012CC451002CC462FB4CC473CD452
+:10012000CC486624CC495563CC4A2D42CC4B300296
+:10013000CC4C13D2CC4D2ED2CC4E3002CC4F100230
+:10014000CC502FD2CC513002CC521002CC530004F0
+:10015000CC542942CC553002CC561002CC572092B8
+:10016000CC583012CC591002CC5A5CC3CC5B03176C
+:10017000CC5C2F72CC5D3002CC5E1002CC5F294289
+:10018000CC603002CC611002CC6222CDCC63301D39
+:10019000CC642862CC653012CC661002CC672ED2BB
+:1001A000CC683002CC691002CC6A2D72CC6B300264
+:1001B000CC6C1002CC6D628FCC6E2112CC6F3012E1
+:1001C000CC701002CC715AA3CC722DC2CC73300209
+:1001D000CC741312CC756F72CC761002CC772807D2
+:1001E000CC7831A7CC7920C4CC7A3C24CC7B672452
+:1001F000CC7C1002CC7D2807CC7E3187CC7F20C4FC
+:10020000CC803C24CC816724CC821002CC83251482
+:10021000CC843C64CC856436CC86DFF4CC876436F1
+:10022000CC881002CC8940A4CC8A643CCC8B40168C
+:10023000CC8C8C6CCC8D2B24CC8E3C24CC8F643518
+:10024000CC901002CC912B24CC923C24CC93643AD9
+:10025000CC944025CC958A5ACC961002CC97273165
+:10026000CC983011CC991001CC9AC7A0CC9B01003E
+:10027000CC9CC502CC9D53ACCC9EC503CC9FD5D5A0
+:10028000CCA0C600CCA12A6DCCA2C601CCA32A4C1E
+:10029000CCA4C602CCA50111CCA6C60CCCA7590093
+:1002A000CCA8C710CCA90700CCAAC718CCAB0700B4
+:1002B000CCACC720CCAD4700CCAEC801CCAF7F5092
+:1002C000CCB0C802CCB17760CCB2C803CCB37FCE7F
+:1002D000CCB4C804CCB55700CCB6C805CCB75F11B8
+:1002E000CCB8C806CCB94751CCBAC807CCBB57E18B
+:1002F000CCBCC808CCBD2700CCBEC809CCBF000010
+:10030000CCC0C821CCC10002CCC2C822CCC30014CE
+:10031000CCC4C832CCC51186CCC6C847CCC71E02D7
+:10032000CCC8C013CCC9F341CCCAC01ACCCB04464C
+:10033000CCCCC024CCCD1000CCCEC025CCCF0A0074
+:10034000CCD0C026CCD10C0CCCD2C027CCD30C0C3A
+:10035000CCD4C029CCD500A0CCD6C030CCD70A0094
+:10036000CCD8C03CCCD9001CCCDAC005CCDB7A069A
+:10037000CCDC0000CCDD2731CCDE3011CCDF10012D
+:10038000CCE0C620CCE10000CCE2C621CCE3003FAB
+:10039000CCE4C622CCE50000CCE6C623CCE70000C6
+:1003A000CCE8C624CCE90000CCEAC625CCEB0000A2
+:1003B000CCECC627CCED0000CCEEC628CCEF00007C
+:1003C000CCF0C62CCCF10000CCF20000CCF3280617
+:1003D000CCF43CB6CCF5C161CCF66134CCF76135D8
+:1003E000CCF85443CCF90303CCFA6524CCFB000BC6
+:1003F000CCFC1002CCFD2104CCFE3C24CCFF21051A
+:10040000CD003805CD016524CD02DFF4CD034005D4
+:10041000CD046524CD051002CD065DD3CD070306BE
+:10042000CD082FF7CD0938F7CD0A60B7CD0BDFFD2A
+:10043000CD0C000ACD0D1002CD0E00007CC7AE59C8
+:00000001FF
diff --git a/firmware/cxgb3/ael2005_twx_edc.bin.ihex b/firmware/cxgb3/ael2005_twx_edc.bin.ihex
new file mode 100644 (file)
index 0000000..9b5e9e5
--- /dev/null
@@ -0,0 +1,93 @@
+:10000000CC004009CC0127FFCC02300FCC0340AA22
+:10001000CC04401CCC05401ECC062FF4CC073CD4AD
+:10002000CC082035CC093145CC0A6524CC0B26A25E
+:10003000CC0C3012CC0D1002CC0E29C2CC0F3002E9
+:10004000CC101002CC112072CC123012CC13100242
+:10005000CC1422CDCC15301DCC162E52CC1730121C
+:10006000CC181002CC1928E2CC1A3002CC1B10029A
+:10007000CC1C628FCC1D2AC2CC1E3012CC1F1002A9
+:10008000CC205553CC212AE2CC223002CC231302BF
+:10009000CC24401ECC252BE2CC263012CC271002DB
+:1000A000CC282DA2CC293012CC2A1002CC2B2BA28A
+:1000B000CC2C3002CC2D1002CC2E5EE3CC2F0305CD
+:1000C000CC30400ECC312BC2CC323002CC331002BB
+:1000D000CC342B82CC353012CC361002CC37566360
+:1000E000CC380302CC39401ECC3A6F72CC3B1002A4
+:1000F000CC3C628FCC3D2BE2CC3E3012CC3F100288
+:10010000CC4022CDCC41301DCC422E52CC433012BB
+:10011000CC441002CC452522CC463012CC471002EC
+:10012000CC482DA2CC493012CC4A1002CC4B2CA288
+:10013000CC4C3012CC4D1002CC4E2FA4CC4F3CD422
+:10014000CC506624CC51410BCC5256B3CC5303C493
+:10015000CC542FB2CC553002CC561002CC57220BC7
+:10016000CC58303BCC5956B3CC5A03C3CC5B866BCE
+:10017000CC5C400CCC5D23A2CC5E3012CC5F100274
+:10018000CC602DA2CC613012CC621002CC632CA2C8
+:10019000CC643012CC651002CC662FB4CC673CD452
+:1001A000CC686624CC6956B3CC6A03C3CC6B866B2F
+:1001B000CC6C401CCC6D2205CC6E3035CC6F5B53C3
+:1001C000CC702C52CC713002CC7213C2CC735CC395
+:1001D000CC740317CC752522CC763012CC77100264
+:1001E000CC782DA2CC793012CC7A1002CC7B2B8229
+:1001F000CC7C3012CC7D1002CC7E5663CC7F0303C6
+:10020000CC80401ECC810004CC822C42CC833012A6
+:10021000CC841002CC856F72CC861002CC87628FA2
+:10022000CC882304CC893C84CC8A6436CC8BDFF424
+:10023000CC8C6436CC8D2FF5CC8E3005CC8F865689
+:10024000CC90DFBACC9156A3CC92D05ACC9321C299
+:10025000CC943012CC951392CC96D05ACC9756A30E
+:10026000CC98DFBACC990383CC9A6F72CC9B1002E6
+:10027000CC9C28C5CC9D3005CC9E4178CC9F565354
+:10028000CCA00384CCA122B2CCA23012CCA3100209
+:10029000CCA42BE5CCA53005CCA641E8CCA7565381
+:1002A000CCA80382CCA90002CCAA4258CCAB2474BF
+:1002B000CCAC3C84CCAD6437CCAEDFF4CCAF64378F
+:1002C000CCB02FF5CCB13C05CCB28757CCB3B888B5
+:1002D000CCB49787CCB5DFF4CCB66724CCB7866AAC
+:1002E000CCB86F72CCB91002CCBA2D01CCBB301196
+:1002F000CCBC1001CCBDC620CCBE14E5CCBFC62101
+:10030000CCC0C53DCCC1C622CCC23CBECCC3C623EA
+:10031000CCC44452CCC5C624CCC6C5C5CCC7C625A2
+:10032000CCC8E01ECCC9C627CCCA0000CCCBC6289E
+:10033000CCCC0000CCCDC62BCCCE0000CCCFC62C74
+:10034000CCD00000CCD10000CCD22D01CCD33011C8
+:10035000CCD41001CCD5C620CCD60000CCD7C62139
+:10036000CCD80000CCD9C622CCDA00CECCDBC62358
+:10037000CCDC007FCCDDC624CCDE0032CCDFC62551
+:10038000CCE00000CCE1C627CCE20000CCE3C628DC
+:10039000CCE40000CCE5C62BCCE60000CCE7C62CB4
+:1003A000CCE80000CCE90000CCEA2D01CCEB301108
+:1003B000CCEC1001CCEDC502CCEE609FCCEFC600BA
+:1003C000CCF02A6ECCF1C601CCF22A2CCCF3C60CB0
+:1003D000CCF45400CCF5C710CCF60700CCF7C71806
+:1003E000CCF80700CCF9C720CCFA4700CCFBC728D3
+:1003F000CCFC0700CCFDC729CCFE1207CCFFC801FE
+:10040000CD007F50CD01C802CD027760CD03C80377
+:10041000CD047FCECD05C804CD06520ECD07C8054C
+:10042000CD085C11CD09C806CD0A3C51CD0BC807DB
+:10043000CD0C4061CD0DC808CD0E49C1CD0FC80906
+:10044000CD103840CD11C80ACD120000CD13C821FF
+:10045000CD140002CD15C822CD160046CD17C844D4
+:10046000CD18182FCD19C013CD1AF341CD1BC01ACA
+:10047000CD1C0446CD1DC024CD1E1000CD1FC025AF
+:10048000CD200A00CD21C026CD220C0CCD23C027C3
+:10049000CD240C0CCD25C029CD2600A0CD27C03001
+:1004A000CD280A00CD29C03CCD2A001CCD2B000050
+:1004B000CD2C2B84CD2D3C74CD2E6435CD2FDFF487
+:1004C000CD306435CD312806CD323006CD3385654B
+:1004D000CD342B24CD353C24CD366436CD371002B7
+:1004E000CD382B24CD393C24CD3A6436CD3B404524
+:1004F000CD3C8656CD3D1002CD3E2807CD3F31A7DD
+:10050000CD4020C4CD413C24CD426724CD431002D0
+:10051000CD442807CD453187CD4620C4CD473C2466
+:10052000CD486724CD491002CD4A2514CD4B3C64FB
+:10053000CD4C6436CD4DDFF4CD4E6436CD4F100238
+:10054000CD502806CD513CB6CD52C161CD5361345A
+:10055000CD546135CD555443CD560303CD57652455
+:10056000CD58000BCD591002CD5AD019CD5B2104C6
+:10057000CD5C3C24CD5D2105CD5E3805CD5F652485
+:10058000CD60DFF4CD614005CD626524CD632E8D55
+:10059000CD64303DCD655DD3CD660306CD672FF7C5
+:1005A000CD6838F7CD6960B7CD6ADFFDCD6B000A45
+:0C05B000CD6C1002CD6D000052A76B0E48
+:00000001FF
diff --git a/firmware/cxgb3/ael2020_twx_edc.bin.ihex b/firmware/cxgb3/ael2020_twx_edc.bin.ihex
new file mode 100644 (file)
index 0000000..8b1337f
--- /dev/null
@@ -0,0 +1,100 @@
+:10000000D8004009D8012FFFD802300FD80340AAEA
+:10001000D804401CD805401ED8062FF4D8073DC48C
+:10002000D8082035D8093035D80A6524D80B2CB229
+:10003000D80C3012D80D1002D80E26E2D80F30227C
+:10004000D8101002D81127D2D8123022D81310029B
+:10005000D8142822D8153012D8161002D817249296
+:10006000D8183022D8191002D81A2772D81B30128B
+:10007000D81C1002D81D23D2D81E3022D81F10023F
+:10008000D82022CDD821301DD82227F2D8233022E3
+:10009000D8241002D8255553D8260307D82725225F
+:1000A000D8283022D8291002D82A2142D82B301241
+:1000B000D82C1002D82D4016D82E5E63D82F0344BA
+:1000C000D8302142D8313012D8321002D833400E05
+:1000D000D8342522D8353022D8361002D8372B52C2
+:1000E000D8383012D8391002D83A2742D83B3022BB
+:1000F000D83C1002D83D25E2D83E3022D83F10022D
+:10010000D8402FA4D8413DC4D8426624D843414B9F
+:10011000D84456B3D84503C6D846866BD847400C5A
+:10012000D8482712D8493012D84A1002D84B2C4B45
+:10013000D84C309BD84D56B3D84E03C3D84F866B9E
+:10014000D850400CD8512272D8523022D8531002C5
+:10015000D8542742D8553022D8561002D85725E215
+:10016000D8583022D8591002D85A2FB4D85B3DC481
+:10017000D85C6624D85D56B3D85E03C3D85F866B5F
+:10018000D860401CD8612C45D8623095D8635B5349
+:10019000D8642372D8653012D86613C2D8675CC39E
+:1001A000D8682712D8693012D86A1312D86B2B522C
+:1001B000D86C3012D86D1002D86E2742D86F30221A
+:1001C000D8701002D8712582D8723022D8731002EC
+:1001D000D8742142D8753012D8761002D877628F41
+:1001E000D8782985D87933A5D87A25E2D87B3022EA
+:1001F000D87C1002D87D5653D87E03D2D87F401EBB
+:10020000D8806F72D8811002D882628FD88323047D
+:10021000D8843C84D8856436D886DFF4D8876436A1
+:10022000D8882FF5D8893005D88A8656D88BDFBA7A
+:10023000D88C56A3D88DD05AD88E2972D88F301228
+:10024000D8901392D891D05AD89256A3D893DFBAA7
+:10025000D8940383D8956F72D8961002D8972B45FF
+:10026000D8983005D8994178D89A5653D89B0384AA
+:10027000D89C2A62D89D3012D89E1002D89F2F0594
+:10028000D8A03005D8A141C8D8A25653D8A303821C
+:10029000D8A40002D8A54218D8A62474D8A73C84B4
+:1002A000D8A86437D8A9DFF4D8AA6437D8AB2FF51B
+:1002B000D8AC3C05D8AD8757D8AEB888D8AF9787AB
+:1002C000D8B0DFF4D8B16724D8B2866AD8B36F72D9
+:1002D000D8B41002D8B52641D8B63021D8B710010D
+:1002E000D8B8C620D8B90000D8BAC621D8BB0000FB
+:1002F000D8BCC622D8BD00CED8BEC623D8BF007F8A
+:10030000D8C0C624D8C10032D8C2C625D8C3000080
+:10031000D8C4C627D8C50000D8C6C628D8C700008C
+:10032000D8C8C62CD8C90000D8CA0000D8CB2641EE
+:10033000D8CC3021D8CD1001D8CEC502D8CF53ACFF
+:10034000D8D0C503D8D12CD3D8D2C600D8D32A6EE2
+:10035000D8D4C601D8D52A2CD8D6C605D8D7555753
+:10036000D8D8C60CD8D95400D8DAC710D8DB0700C3
+:10037000D8DCC711D8DD0F06D8DEC718D8DF0700D4
+:10038000D8E0C719D8E10F06D8E2C720D8E3470064
+:10039000D8E4C721D8E50F06D8E6C728D8E7070074
+:1003A000D8E8C729D8E91207D8EAC801D8EB7F50A6
+:1003B000D8ECC802D8ED7760D8EEC803D8EF7FCE6E
+:1003C000D8F0C804D8F1520ED8F2C805D8F35C11A1
+:1003D000D8F4C806D8F53C51D8F6C807D8F740611C
+:1003E000D8F8C808D8F949C1D8FAC809D8FB3840A4
+:1003F000D8FCC80AD8FD0000D8FEC821D8FF0002EA
+:10040000D900C822D9010046D902C844D903182FFF
+:10041000D904C013D905F341D906C084D9070030E7
+:10042000D908C904D9091401D90ACB0CD90B000485
+:10043000D90CCB0ED90DA00AD90ECB0FD90FC0C045
+:10044000D910CB10D911C0C0D912CB11D91300A02B
+:10045000D914CB12D9150007D916C241D917A0005B
+:10046000D918C243D9197FE0D91AC604D91B000E86
+:10047000D91CC609D91D00F5D91EC611D91F000EF9
+:10048000D920C660D9219600D922C687D923000475
+:10049000D924C60AD92504F5D9260000D927264132
+:1004A000D9283021D9291001D92AC620D92B14E501
+:1004B000D92CC621D92DC53DD92EC622D92F3CBE57
+:1004C000D930C623D9314452D932C624D933C5C50F
+:1004D000D934C625D935E01ED936C627D93700000C
+:1004E000D938C628D9390000D93AC62CD93B0000E2
+:1004F000D93C0000D93D2B84D93E3C74D93F6435AA
+:10050000D940DFF4D9416435D9422806D9433006B1
+:10051000D9448565D9452B24D9463C24D94764362E
+:10052000D9481002D9492B24D94A3C24D94B6436E6
+:10053000D94C4045D94D8656D94E5663D94F030202
+:10054000D950401ED9511002D9522807D95331A78A
+:10055000D95420C4D9553C24D9566724D957100200
+:10056000D9582807D9593187D95A20C4D95B3C2496
+:10057000D95C6724D95D1002D95E24F4D95F3C644C
+:10058000D9606436D961DFF4D9626436D963100268
+:10059000D9642006D9653D76D966C161D9676134D1
+:1005A000D9686135D9695443D96A0303D96B652485
+:1005B000D96C00FBD96D1002D96E20D4D96F3C24C0
+:1005C000D9702025D9713005D9726524D9731002EC
+:1005D000D974D019D9752104D9763C24D97721054D
+:1005E000D9783805D9796524D97ADFF4D97B4005E3
+:1005F000D97C6524D97D2E8DD97E303DD97F2408C4
+:10060000D98035D8D9815DD3D9820307D98388872A
+:10061000D98463A7D9858887D98663A7D987DFFD61
+:10062000D98800F9D9891002D98A0000878C30D97D
+:00000001FF
index 210acaf..3ff8bdd 100644 (file)
@@ -432,7 +432,6 @@ vfs_rejected_lock:
        list_del_init(&fl->fl_u.afs.link);
        if (list_empty(&vnode->granted_locks))
                afs_defer_unlock(vnode, key);
-       spin_unlock(&vnode->lock);
        goto abort_attempt;
 }
 
index 76da125..d065b2c 100644 (file)
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -485,6 +485,8 @@ static inline void really_put_req(struct kioctx *ctx, struct kiocb *req)
 {
        assert_spin_locked(&ctx->ctx_lock);
 
+       if (req->ki_eventfd != NULL)
+               eventfd_ctx_put(req->ki_eventfd);
        if (req->ki_dtor)
                req->ki_dtor(req);
        if (req->ki_iovec != &req->ki_inline_vec)
@@ -509,8 +511,6 @@ static void aio_fput_routine(struct work_struct *data)
                /* Complete the fput(s) */
                if (req->ki_filp != NULL)
                        __fput(req->ki_filp);
-               if (req->ki_eventfd != NULL)
-                       __fput(req->ki_eventfd);
 
                /* Link the iocb into the context's free list */
                spin_lock_irq(&ctx->ctx_lock);
@@ -528,8 +528,6 @@ static void aio_fput_routine(struct work_struct *data)
  */
 static int __aio_put_req(struct kioctx *ctx, struct kiocb *req)
 {
-       int schedule_putreq = 0;
-
        dprintk(KERN_DEBUG "aio_put(%p): f_count=%ld\n",
                req, atomic_long_read(&req->ki_filp->f_count));
 
@@ -549,24 +547,16 @@ static int __aio_put_req(struct kioctx *ctx, struct kiocb *req)
         * we would not be holding the last reference to the file*, so
         * this function will be executed w/out any aio kthread wakeup.
         */
-       if (unlikely(atomic_long_dec_and_test(&req->ki_filp->f_count)))
-               schedule_putreq++;
-       else
-               req->ki_filp = NULL;
-       if (req->ki_eventfd != NULL) {
-               if (unlikely(atomic_long_dec_and_test(&req->ki_eventfd->f_count)))
-                       schedule_putreq++;
-               else
-                       req->ki_eventfd = NULL;
-       }
-       if (unlikely(schedule_putreq)) {
+       if (unlikely(atomic_long_dec_and_test(&req->ki_filp->f_count))) {
                get_ioctx(ctx);
                spin_lock(&fput_lock);
                list_add(&req->ki_list, &fput_head);
                spin_unlock(&fput_lock);
                queue_work(aio_wq, &fput_work);
-       } else
+       } else {
+               req->ki_filp = NULL;
                really_put_req(ctx, req);
+       }
        return 1;
 }
 
@@ -1622,7 +1612,7 @@ static int io_submit_one(struct kioctx *ctx, struct iocb __user *user_iocb,
                 * an eventfd() fd, and will be signaled for each completed
                 * event using the eventfd_signal() function.
                 */
-               req->ki_eventfd = eventfd_fget((int) iocb->aio_resfd);
+               req->ki_eventfd = eventfd_ctx_fdget((int) iocb->aio_resfd);
                if (IS_ERR(req->ki_eventfd)) {
                        ret = PTR_ERR(req->ki_eventfd);
                        req->ki_eventfd = NULL;
index 9fa212b..b7c1603 100644 (file)
@@ -1522,11 +1522,11 @@ static int fill_note_info(struct elfhdr *elf, int phdrs,
        info->thread = NULL;
 
        psinfo = kmalloc(sizeof(*psinfo), GFP_KERNEL);
-       fill_note(&info->psinfo, "CORE", NT_PRPSINFO, sizeof(*psinfo), psinfo);
-
        if (psinfo == NULL)
                return 0;
 
+       fill_note(&info->psinfo, "CORE", NT_PRPSINFO, sizeof(*psinfo), psinfo);
+
        /*
         * Figure out how many notes we're going to need for each thread.
         */
@@ -1929,7 +1929,10 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file, un
        elf = kmalloc(sizeof(*elf), GFP_KERNEL);
        if (!elf)
                goto out;
-       
+       /*
+        * The number of segs are recored into ELF header as 16bit value.
+        * Please check DEFAULT_MAX_MAP_COUNT definition when you modify here.
+        */
        segs = current->mm->map_count;
 #ifdef ELF_CORE_EXTRA_PHDRS
        segs += ELF_CORE_EXTRA_PHDRS;
index 31c46a2..49a34e7 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * bio-integrity.c - bio data integrity extensions
  *
- * Copyright (C) 2007, 2008 Oracle Corporation
+ * Copyright (C) 2007, 2008, 2009 Oracle Corporation
  * Written by: Martin K. Petersen <martin.petersen@oracle.com>
  *
  * This program is free software; you can redistribute it and/or
 #include <linux/bio.h>
 #include <linux/workqueue.h>
 
-static struct kmem_cache *bio_integrity_slab __read_mostly;
-static mempool_t *bio_integrity_pool;
-static struct bio_set *integrity_bio_set;
+struct integrity_slab {
+       struct kmem_cache *slab;
+       unsigned short nr_vecs;
+       char name[8];
+};
+
+#define IS(x) { .nr_vecs = x, .name = "bip-"__stringify(x) }
+struct integrity_slab bip_slab[BIOVEC_NR_POOLS] __read_mostly = {
+       IS(1), IS(4), IS(16), IS(64), IS(128), IS(BIO_MAX_PAGES),
+};
+#undef IS
+
 static struct workqueue_struct *kintegrityd_wq;
 
+static inline unsigned int vecs_to_idx(unsigned int nr)
+{
+       switch (nr) {
+       case 1:
+               return 0;
+       case 2 ... 4:
+               return 1;
+       case 5 ... 16:
+               return 2;
+       case 17 ... 64:
+               return 3;
+       case 65 ... 128:
+               return 4;
+       case 129 ... BIO_MAX_PAGES:
+               return 5;
+       default:
+               BUG();
+       }
+}
+
+static inline int use_bip_pool(unsigned int idx)
+{
+       if (idx == BIOVEC_NR_POOLS)
+               return 1;
+
+       return 0;
+}
+
 /**
- * bio_integrity_alloc - Allocate integrity payload and attach it to bio
+ * bio_integrity_alloc_bioset - Allocate integrity payload and attach it to bio
  * @bio:       bio to attach integrity metadata to
  * @gfp_mask:  Memory allocation mask
  * @nr_vecs:   Number of integrity metadata scatter-gather elements
+ * @bs:                bio_set to allocate from
  *
  * Description: This function prepares a bio for attaching integrity
  * metadata.  nr_vecs specifies the maximum number of pages containing
  * integrity metadata that can be attached.
  */
-struct bio_integrity_payload *bio_integrity_alloc(struct bio *bio,
-                                                 gfp_t gfp_mask,
-                                                 unsigned int nr_vecs)
+struct bio_integrity_payload *bio_integrity_alloc_bioset(struct bio *bio,
+                                                        gfp_t gfp_mask,
+                                                        unsigned int nr_vecs,
+                                                        struct bio_set *bs)
 {
        struct bio_integrity_payload *bip;
-       struct bio_vec *iv;
-       unsigned long idx;
+       unsigned int idx = vecs_to_idx(nr_vecs);
 
        BUG_ON(bio == NULL);
+       bip = NULL;
 
-       bip = mempool_alloc(bio_integrity_pool, gfp_mask);
-       if (unlikely(bip == NULL)) {
-               printk(KERN_ERR "%s: could not alloc bip\n", __func__);
-               return NULL;
-       }
+       /* Lower order allocations come straight from slab */
+       if (!use_bip_pool(idx))
+               bip = kmem_cache_alloc(bip_slab[idx].slab, gfp_mask);
 
-       memset(bip, 0, sizeof(*bip));
+       /* Use mempool if lower order alloc failed or max vecs were requested */
+       if (bip == NULL) {
+               bip = mempool_alloc(bs->bio_integrity_pool, gfp_mask);
 
-       iv = bvec_alloc_bs(gfp_mask, nr_vecs, &idx, integrity_bio_set);
-       if (unlikely(iv == NULL)) {
-               printk(KERN_ERR "%s: could not alloc bip_vec\n", __func__);
-               mempool_free(bip, bio_integrity_pool);
-               return NULL;
+               if (unlikely(bip == NULL)) {
+                       printk(KERN_ERR "%s: could not alloc bip\n", __func__);
+                       return NULL;
+               }
        }
 
-       bip->bip_pool = idx;
-       bip->bip_vec = iv;
+       memset(bip, 0, sizeof(*bip));
+
+       bip->bip_slab = idx;
        bip->bip_bio = bio;
        bio->bi_integrity = bip;
 
        return bip;
 }
+EXPORT_SYMBOL(bio_integrity_alloc_bioset);
+
+/**
+ * bio_integrity_alloc - Allocate integrity payload and attach it to bio
+ * @bio:       bio to attach integrity metadata to
+ * @gfp_mask:  Memory allocation mask
+ * @nr_vecs:   Number of integrity metadata scatter-gather elements
+ *
+ * Description: This function prepares a bio for attaching integrity
+ * metadata.  nr_vecs specifies the maximum number of pages containing
+ * integrity metadata that can be attached.
+ */
+struct bio_integrity_payload *bio_integrity_alloc(struct bio *bio,
+                                                 gfp_t gfp_mask,
+                                                 unsigned int nr_vecs)
+{
+       return bio_integrity_alloc_bioset(bio, gfp_mask, nr_vecs, fs_bio_set);
+}
 EXPORT_SYMBOL(bio_integrity_alloc);
 
 /**
  * bio_integrity_free - Free bio integrity payload
  * @bio:       bio containing bip to be freed
+ * @bs:                bio_set this bio was allocated from
  *
  * Description: Used to free the integrity portion of a bio. Usually
  * called from bio_free().
  */
-void bio_integrity_free(struct bio *bio)
+void bio_integrity_free(struct bio *bio, struct bio_set *bs)
 {
        struct bio_integrity_payload *bip = bio->bi_integrity;
 
@@ -92,8 +150,10 @@ void bio_integrity_free(struct bio *bio)
            && bip->bip_buf != NULL)
                kfree(bip->bip_buf);
 
-       bvec_free_bs(integrity_bio_set, bip->bip_vec, bip->bip_pool);
-       mempool_free(bip, bio_integrity_pool);
+       if (use_bip_pool(bip->bip_slab))
+               mempool_free(bip, bs->bio_integrity_pool);
+       else
+               kmem_cache_free(bip_slab[bip->bip_slab].slab, bip);
 
        bio->bi_integrity = NULL;
 }
@@ -114,7 +174,7 @@ int bio_integrity_add_page(struct bio *bio, struct page *page,
        struct bio_integrity_payload *bip = bio->bi_integrity;
        struct bio_vec *iv;
 
-       if (bip->bip_vcnt >= bvec_nr_vecs(bip->bip_pool)) {
+       if (bip->bip_vcnt >= bvec_nr_vecs(bip->bip_slab)) {
                printk(KERN_ERR "%s: bip_vec full\n", __func__);
                return 0;
        }
@@ -647,8 +707,8 @@ void bio_integrity_split(struct bio *bio, struct bio_pair *bp, int sectors)
        bp->iv1 = bip->bip_vec[0];
        bp->iv2 = bip->bip_vec[0];
 
-       bp->bip1.bip_vec = &bp->iv1;
-       bp->bip2.bip_vec = &bp->iv2;
+       bp->bip1.bip_vec[0] = bp->iv1;
+       bp->bip2.bip_vec[0] = bp->iv2;
 
        bp->iv1.bv_len = sectors * bi->tuple_size;
        bp->iv2.bv_offset += sectors * bi->tuple_size;
@@ -667,17 +727,19 @@ EXPORT_SYMBOL(bio_integrity_split);
  * @bio:       New bio
  * @bio_src:   Original bio
  * @gfp_mask:  Memory allocation mask
+ * @bs:                bio_set to allocate bip from
  *
  * Description:        Called to allocate a bip when cloning a bio
  */
-int bio_integrity_clone(struct bio *bio, struct bio *bio_src, gfp_t gfp_mask)
+int bio_integrity_clone(struct bio *bio, struct bio *bio_src,
+                       gfp_t gfp_mask, struct bio_set *bs)
 {
        struct bio_integrity_payload *bip_src = bio_src->bi_integrity;
        struct bio_integrity_payload *bip;
 
        BUG_ON(bip_src == NULL);
 
-       bip = bio_integrity_alloc(bio, gfp_mask, bip_src->bip_vcnt);
+       bip = bio_integrity_alloc_bioset(bio, gfp_mask, bip_src->bip_vcnt, bs);
 
        if (bip == NULL)
                return -EIO;
@@ -693,25 +755,43 @@ int bio_integrity_clone(struct bio *bio, struct bio *bio_src, gfp_t gfp_mask)
 }
 EXPORT_SYMBOL(bio_integrity_clone);
 
-static int __init bio_integrity_init(void)
+int bioset_integrity_create(struct bio_set *bs, int pool_size)
 {
-       kintegrityd_wq = create_workqueue("kintegrityd");
+       unsigned int max_slab = vecs_to_idx(BIO_MAX_PAGES);
+
+       bs->bio_integrity_pool =
+               mempool_create_slab_pool(pool_size, bip_slab[max_slab].slab);
 
+       if (!bs->bio_integrity_pool)
+               return -1;
+
+       return 0;
+}
+EXPORT_SYMBOL(bioset_integrity_create);
+
+void bioset_integrity_free(struct bio_set *bs)
+{
+       if (bs->bio_integrity_pool)
+               mempool_destroy(bs->bio_integrity_pool);
+}
+EXPORT_SYMBOL(bioset_integrity_free);
+
+void __init bio_integrity_init(void)
+{
+       unsigned int i;
+
+       kintegrityd_wq = create_workqueue("kintegrityd");
        if (!kintegrityd_wq)
                panic("Failed to create kintegrityd\n");
 
-       bio_integrity_slab = KMEM_CACHE(bio_integrity_payload,
-                                       SLAB_HWCACHE_ALIGN|SLAB_PANIC);
+       for (i = 0 ; i < BIOVEC_NR_POOLS ; i++) {
+               unsigned int size;
 
-       bio_integrity_pool = mempool_create_slab_pool(BIO_POOL_SIZE,
-                                                     bio_integrity_slab);
-       if (!bio_integrity_pool)
-               panic("bio_integrity: can't allocate bip pool\n");
+               size = sizeof(struct bio_integrity_payload)
+                       + bip_slab[i].nr_vecs * sizeof(struct bio_vec);
 
-       integrity_bio_set = bioset_create(BIO_POOL_SIZE, 0);
-       if (!integrity_bio_set)
-               panic("bio_integrity: can't allocate bio_set\n");
-
-       return 0;
+               bip_slab[i].slab =
+                       kmem_cache_create(bip_slab[i].name, size, 0,
+                                         SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL);
+       }
 }
-subsys_initcall(bio_integrity_init);
index 24c9140..1486b19 100644 (file)
--- a/fs/bio.c
+++ b/fs/bio.c
@@ -238,7 +238,7 @@ void bio_free(struct bio *bio, struct bio_set *bs)
                bvec_free_bs(bs, bio->bi_io_vec, BIO_POOL_IDX(bio));
 
        if (bio_integrity(bio))
-               bio_integrity_free(bio);
+               bio_integrity_free(bio, bs);
 
        /*
         * If we have front padding, adjust the bio pointer before freeing
@@ -341,7 +341,7 @@ struct bio *bio_alloc(gfp_t gfp_mask, int nr_iovecs)
 static void bio_kmalloc_destructor(struct bio *bio)
 {
        if (bio_integrity(bio))
-               bio_integrity_free(bio);
+               bio_integrity_free(bio, fs_bio_set);
        kfree(bio);
 }
 
@@ -472,7 +472,7 @@ struct bio *bio_clone(struct bio *bio, gfp_t gfp_mask)
        if (bio_integrity(bio)) {
                int ret;
 
-               ret = bio_integrity_clone(b, bio, gfp_mask);
+               ret = bio_integrity_clone(b, bio, gfp_mask, fs_bio_set);
 
                if (ret < 0) {
                        bio_put(b);
@@ -1539,6 +1539,7 @@ void bioset_free(struct bio_set *bs)
        if (bs->bio_pool)
                mempool_destroy(bs->bio_pool);
 
+       bioset_integrity_free(bs);
        biovec_free_pools(bs);
        bio_put_slab(bs);
 
@@ -1579,6 +1580,9 @@ struct bio_set *bioset_create(unsigned int pool_size, unsigned int front_pad)
        if (!bs->bio_pool)
                goto bad;
 
+       if (bioset_integrity_create(bs, pool_size))
+               goto bad;
+
        if (!biovec_create_pools(bs, pool_size))
                return bs;
 
@@ -1616,6 +1620,7 @@ static int __init init_bio(void)
        if (!bio_slabs)
                panic("bio: can't allocate bios\n");
 
+       bio_integrity_init();
        biovec_init_slabs();
 
        fs_bio_set = bioset_create(BIO_POOL_SIZE, 0);
index 7f88628..6e4f6c5 100644 (file)
@@ -299,8 +299,8 @@ int btrfs_start_workers(struct btrfs_workers *workers, int num_workers)
                                           "btrfs-%s-%d", workers->name,
                                           workers->num_workers + i);
                if (IS_ERR(worker->task)) {
-                       kfree(worker);
                        ret = PTR_ERR(worker->task);
+                       kfree(worker);
                        goto fail;
                }
 
index 2779c2f..98a8738 100644 (file)
@@ -2074,8 +2074,7 @@ static inline int btrfs_insert_empty_item(struct btrfs_trans_handle *trans,
 int btrfs_next_leaf(struct btrfs_root *root, struct btrfs_path *path);
 int btrfs_prev_leaf(struct btrfs_root *root, struct btrfs_path *path);
 int btrfs_leaf_free_space(struct btrfs_root *root, struct extent_buffer *leaf);
-int btrfs_drop_snapshot(struct btrfs_trans_handle *trans, struct btrfs_root
-                       *root);
+int btrfs_drop_snapshot(struct btrfs_root *root, int update_ref);
 int btrfs_drop_subtree(struct btrfs_trans_handle *trans,
                        struct btrfs_root *root,
                        struct extent_buffer *node,
index edc7d20..a5aca39 100644 (file)
@@ -990,15 +990,13 @@ static inline int extent_ref_type(u64 parent, u64 owner)
        return type;
 }
 
-static int find_next_key(struct btrfs_path *path, struct btrfs_key *key)
+static int find_next_key(struct btrfs_path *path, int level,
+                        struct btrfs_key *key)
 
 {
-       int level;
-       BUG_ON(!path->keep_locks);
-       for (level = 0; level < BTRFS_MAX_LEVEL; level++) {
+       for (; level < BTRFS_MAX_LEVEL; level++) {
                if (!path->nodes[level])
                        break;
-               btrfs_assert_tree_locked(path->nodes[level]);
                if (path->slots[level] + 1 >=
                    btrfs_header_nritems(path->nodes[level]))
                        continue;
@@ -1158,7 +1156,8 @@ int lookup_inline_extent_backref(struct btrfs_trans_handle *trans,
                 * For simplicity, we just do not add new inline back
                 * ref if there is any kind of item for this block
                 */
-               if (find_next_key(path, &key) == 0 && key.objectid == bytenr &&
+               if (find_next_key(path, 0, &key) == 0 &&
+                   key.objectid == bytenr &&
                    key.type < BTRFS_BLOCK_GROUP_ITEM_KEY) {
                        err = -EAGAIN;
                        goto out;
@@ -2697,7 +2696,7 @@ 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 bytes_pinned, %llu bytes_readonly, %llu may use "
                       "%llu total\n", (unsigned long long)bytes,
                       (unsigned long long)data_sinfo->bytes_delalloc,
                       (unsigned long long)data_sinfo->bytes_used,
@@ -4128,6 +4127,7 @@ struct extent_buffer *btrfs_alloc_free_block(struct btrfs_trans_handle *trans,
        return buf;
 }
 
+#if 0
 int btrfs_drop_leaf_ref(struct btrfs_trans_handle *trans,
                        struct btrfs_root *root, struct extent_buffer *leaf)
 {
@@ -4171,8 +4171,6 @@ int btrfs_drop_leaf_ref(struct btrfs_trans_handle *trans,
        return 0;
 }
 
-#if 0
-
 static noinline int cache_drop_leaf_ref(struct btrfs_trans_handle *trans,
                                        struct btrfs_root *root,
                                        struct btrfs_leaf_ref *ref)
@@ -4553,262 +4551,471 @@ out:
 }
 #endif
 
+struct walk_control {
+       u64 refs[BTRFS_MAX_LEVEL];
+       u64 flags[BTRFS_MAX_LEVEL];
+       struct btrfs_key update_progress;
+       int stage;
+       int level;
+       int shared_level;
+       int update_ref;
+       int keep_locks;
+};
+
+#define DROP_REFERENCE 1
+#define UPDATE_BACKREF 2
+
 /*
- * helper function for drop_subtree, this function is similar to
- * walk_down_tree. The main difference is that it checks reference
- * counts while tree blocks are locked.
+ * hepler to process tree block while walking down the tree.
+ *
+ * when wc->stage == DROP_REFERENCE, this function checks
+ * reference count of the block. if the block is shared and
+ * we need update back refs for the subtree rooted at the
+ * block, this function changes wc->stage to UPDATE_BACKREF
+ *
+ * when wc->stage == UPDATE_BACKREF, this function updates
+ * back refs for pointers in the block.
+ *
+ * NOTE: return value 1 means we should stop walking down.
  */
-static noinline int walk_down_tree(struct btrfs_trans_handle *trans,
+static noinline int walk_down_proc(struct btrfs_trans_handle *trans,
                                   struct btrfs_root *root,
-                                  struct btrfs_path *path, int *level)
+                                  struct btrfs_path *path,
+                                  struct walk_control *wc)
 {
-       struct extent_buffer *next;
-       struct extent_buffer *cur;
-       struct extent_buffer *parent;
-       u64 bytenr;
-       u64 ptr_gen;
-       u64 refs;
-       u64 flags;
-       u32 blocksize;
+       int level = wc->level;
+       struct extent_buffer *eb = path->nodes[level];
+       struct btrfs_key key;
+       u64 flag = BTRFS_BLOCK_FLAG_FULL_BACKREF;
        int ret;
 
-       cur = path->nodes[*level];
-       ret = btrfs_lookup_extent_info(trans, root, cur->start, cur->len,
-                                      &refs, &flags);
-       BUG_ON(ret);
-       if (refs > 1)
-               goto out;
+       if (wc->stage == UPDATE_BACKREF &&
+           btrfs_header_owner(eb) != root->root_key.objectid)
+               return 1;
 
-       BUG_ON(!(flags & BTRFS_BLOCK_FLAG_FULL_BACKREF));
+       /*
+        * when reference count of tree block is 1, it won't increase
+        * again. once full backref flag is set, we never clear it.
+        */
+       if ((wc->stage == DROP_REFERENCE && wc->refs[level] != 1) ||
+           (wc->stage == UPDATE_BACKREF && !(wc->flags[level] & flag))) {
+               BUG_ON(!path->locks[level]);
+               ret = btrfs_lookup_extent_info(trans, root,
+                                              eb->start, eb->len,
+                                              &wc->refs[level],
+                                              &wc->flags[level]);
+               BUG_ON(ret);
+               BUG_ON(wc->refs[level] == 0);
+       }
 
-       while (*level >= 0) {
-               cur = path->nodes[*level];
-               if (*level == 0) {
-                       ret = btrfs_drop_leaf_ref(trans, root, cur);
-                       BUG_ON(ret);
-                       clean_tree_block(trans, root, cur);
-                       break;
-               }
-               if (path->slots[*level] >= btrfs_header_nritems(cur)) {
-                       clean_tree_block(trans, root, cur);
-                       break;
+       if (wc->stage == DROP_REFERENCE &&
+           wc->update_ref && wc->refs[level] > 1) {
+               BUG_ON(eb == root->node);
+               BUG_ON(path->slots[level] > 0);
+               if (level == 0)
+                       btrfs_item_key_to_cpu(eb, &key, path->slots[level]);
+               else
+                       btrfs_node_key_to_cpu(eb, &key, path->slots[level]);
+               if (btrfs_header_owner(eb) == root->root_key.objectid &&
+                   btrfs_comp_cpu_keys(&key, &wc->update_progress) >= 0) {
+                       wc->stage = UPDATE_BACKREF;
+                       wc->shared_level = level;
                }
+       }
 
-               bytenr = btrfs_node_blockptr(cur, path->slots[*level]);
-               blocksize = btrfs_level_size(root, *level - 1);
-               ptr_gen = btrfs_node_ptr_generation(cur, path->slots[*level]);
+       if (wc->stage == DROP_REFERENCE) {
+               if (wc->refs[level] > 1)
+                       return 1;
 
-               next = read_tree_block(root, bytenr, blocksize, ptr_gen);
-               btrfs_tree_lock(next);
-               btrfs_set_lock_blocking(next);
+               if (path->locks[level] && !wc->keep_locks) {
+                       btrfs_tree_unlock(eb);
+                       path->locks[level] = 0;
+               }
+               return 0;
+       }
 
-               ret = btrfs_lookup_extent_info(trans, root, bytenr, blocksize,
-                                              &refs, &flags);
+       /* wc->stage == UPDATE_BACKREF */
+       if (!(wc->flags[level] & flag)) {
+               BUG_ON(!path->locks[level]);
+               ret = btrfs_inc_ref(trans, root, eb, 1);
                BUG_ON(ret);
-               if (refs > 1) {
-                       parent = path->nodes[*level];
-                       ret = btrfs_free_extent(trans, root, bytenr,
-                                               blocksize, parent->start,
-                                               btrfs_header_owner(parent),
-                                               *level - 1, 0);
+               ret = btrfs_dec_ref(trans, root, eb, 0);
+               BUG_ON(ret);
+               ret = btrfs_set_disk_extent_flags(trans, root, eb->start,
+                                                 eb->len, flag, 0);
+               BUG_ON(ret);
+               wc->flags[level] |= flag;
+       }
+
+       /*
+        * the block is shared by multiple trees, so it's not good to
+        * keep the tree lock
+        */
+       if (path->locks[level] && level > 0) {
+               btrfs_tree_unlock(eb);
+               path->locks[level] = 0;
+       }
+       return 0;
+}
+
+/*
+ * hepler to process tree block while walking up the tree.
+ *
+ * when wc->stage == DROP_REFERENCE, this function drops
+ * reference count on the block.
+ *
+ * when wc->stage == UPDATE_BACKREF, this function changes
+ * wc->stage back to DROP_REFERENCE if we changed wc->stage
+ * to UPDATE_BACKREF previously while processing the block.
+ *
+ * NOTE: return value 1 means we should stop walking up.
+ */
+static noinline int walk_up_proc(struct btrfs_trans_handle *trans,
+                                struct btrfs_root *root,
+                                struct btrfs_path *path,
+                                struct walk_control *wc)
+{
+       int ret = 0;
+       int level = wc->level;
+       struct extent_buffer *eb = path->nodes[level];
+       u64 parent = 0;
+
+       if (wc->stage == UPDATE_BACKREF) {
+               BUG_ON(wc->shared_level < level);
+               if (level < wc->shared_level)
+                       goto out;
+
+               BUG_ON(wc->refs[level] <= 1);
+               ret = find_next_key(path, level + 1, &wc->update_progress);
+               if (ret > 0)
+                       wc->update_ref = 0;
+
+               wc->stage = DROP_REFERENCE;
+               wc->shared_level = -1;
+               path->slots[level] = 0;
+
+               /*
+                * check reference count again if the block isn't locked.
+                * we should start walking down the tree again if reference
+                * count is one.
+                */
+               if (!path->locks[level]) {
+                       BUG_ON(level == 0);
+                       btrfs_tree_lock(eb);
+                       btrfs_set_lock_blocking(eb);
+                       path->locks[level] = 1;
+
+                       ret = btrfs_lookup_extent_info(trans, root,
+                                                      eb->start, eb->len,
+                                                      &wc->refs[level],
+                                                      &wc->flags[level]);
                        BUG_ON(ret);
-                       path->slots[*level]++;
-                       btrfs_tree_unlock(next);
-                       free_extent_buffer(next);
-                       continue;
+                       BUG_ON(wc->refs[level] == 0);
+                       if (wc->refs[level] == 1) {
+                               btrfs_tree_unlock(eb);
+                               path->locks[level] = 0;
+                               return 1;
+                       }
+               } else {
+                       BUG_ON(level != 0);
                }
+       }
 
-               BUG_ON(!(flags & BTRFS_BLOCK_FLAG_FULL_BACKREF));
+       /* wc->stage == DROP_REFERENCE */
+       BUG_ON(wc->refs[level] > 1 && !path->locks[level]);
 
-               *level = btrfs_header_level(next);
-               path->nodes[*level] = next;
-               path->slots[*level] = 0;
-               path->locks[*level] = 1;
-               cond_resched();
+       if (wc->refs[level] == 1) {
+               if (level == 0) {
+                       if (wc->flags[level] & BTRFS_BLOCK_FLAG_FULL_BACKREF)
+                               ret = btrfs_dec_ref(trans, root, eb, 1);
+                       else
+                               ret = btrfs_dec_ref(trans, root, eb, 0);
+                       BUG_ON(ret);
+               }
+               /* make block locked assertion in clean_tree_block happy */
+               if (!path->locks[level] &&
+                   btrfs_header_generation(eb) == trans->transid) {
+                       btrfs_tree_lock(eb);
+                       btrfs_set_lock_blocking(eb);
+                       path->locks[level] = 1;
+               }
+               clean_tree_block(trans, root, eb);
+       }
+
+       if (eb == root->node) {
+               if (wc->flags[level] & BTRFS_BLOCK_FLAG_FULL_BACKREF)
+                       parent = eb->start;
+               else
+                       BUG_ON(root->root_key.objectid !=
+                              btrfs_header_owner(eb));
+       } else {
+               if (wc->flags[level + 1] & BTRFS_BLOCK_FLAG_FULL_BACKREF)
+                       parent = path->nodes[level + 1]->start;
+               else
+                       BUG_ON(root->root_key.objectid !=
+                              btrfs_header_owner(path->nodes[level + 1]));
        }
-out:
-       if (path->nodes[*level] == root->node)
-               parent = path->nodes[*level];
-       else
-               parent = path->nodes[*level + 1];
-       bytenr = path->nodes[*level]->start;
-       blocksize = path->nodes[*level]->len;
 
-       ret = btrfs_free_extent(trans, root, bytenr, blocksize, parent->start,
-                               btrfs_header_owner(parent), *level, 0);
+       ret = btrfs_free_extent(trans, root, eb->start, eb->len, parent,
+                               root->root_key.objectid, level, 0);
        BUG_ON(ret);
+out:
+       wc->refs[level] = 0;
+       wc->flags[level] = 0;
+       return ret;
+}
+
+static noinline int walk_down_tree(struct btrfs_trans_handle *trans,
+                                  struct btrfs_root *root,
+                                  struct btrfs_path *path,
+                                  struct walk_control *wc)
+{
+       struct extent_buffer *next;
+       struct extent_buffer *cur;
+       u64 bytenr;
+       u64 ptr_gen;
+       u32 blocksize;
+       int level = wc->level;
+       int ret;
+
+       while (level >= 0) {
+               cur = path->nodes[level];
+               BUG_ON(path->slots[level] >= btrfs_header_nritems(cur));
 
-       if (path->locks[*level]) {
-               btrfs_tree_unlock(path->nodes[*level]);
-               path->locks[*level] = 0;
+               ret = walk_down_proc(trans, root, path, wc);
+               if (ret > 0)
+                       break;
+
+               if (level == 0)
+                       break;
+
+               bytenr = btrfs_node_blockptr(cur, path->slots[level]);
+               blocksize = btrfs_level_size(root, level - 1);
+               ptr_gen = btrfs_node_ptr_generation(cur, path->slots[level]);
+
+               next = read_tree_block(root, bytenr, blocksize, ptr_gen);
+               btrfs_tree_lock(next);
+               btrfs_set_lock_blocking(next);
+
+               level--;
+               BUG_ON(level != btrfs_header_level(next));
+               path->nodes[level] = next;
+               path->slots[level] = 0;
+               path->locks[level] = 1;
+               wc->level = level;
        }
-       free_extent_buffer(path->nodes[*level]);
-       path->nodes[*level] = NULL;
-       *level += 1;
-       cond_resched();
        return 0;
 }
 
-/*
- * helper for dropping snapshots.  This walks back up the tree in the path
- * to find the first node higher up where we haven't yet gone through
- * all the slots
- */
 static noinline int walk_up_tree(struct btrfs_trans_handle *trans,
                                 struct btrfs_root *root,
                                 struct btrfs_path *path,
-                                int *level, int max_level)
+                                struct walk_control *wc, int max_level)
 {
-       struct btrfs_root_item *root_item = &root->root_item;
-       int i;
-       int slot;
+       int level = wc->level;
        int ret;
 
-       for (i = *level; i < max_level && path->nodes[i]; i++) {
-               slot = path->slots[i];
-               if (slot + 1 < btrfs_header_nritems(path->nodes[i])) {
-                       /*
-                        * there is more work to do in this level.
-                        * Update the drop_progress marker to reflect
-                        * the work we've done so far, and then bump
-                        * the slot number
-                        */
-                       path->slots[i]++;
-                       WARN_ON(*level == 0);
-                       if (max_level == BTRFS_MAX_LEVEL) {
-                               btrfs_node_key(path->nodes[i],
-                                              &root_item->drop_progress,
-                                              path->slots[i]);
-                               root_item->drop_level = i;
-                       }
-                       *level = i;
+       path->slots[level] = btrfs_header_nritems(path->nodes[level]);
+       while (level < max_level && path->nodes[level]) {
+               wc->level = level;
+               if (path->slots[level] + 1 <
+                   btrfs_header_nritems(path->nodes[level])) {
+                       path->slots[level]++;
                        return 0;
                } else {
-                       struct extent_buffer *parent;
-
-                       /*
-                        * this whole node is done, free our reference
-                        * on it and go up one level
-                        */
-                       if (path->nodes[*level] == root->node)
-                               parent = path->nodes[*level];
-                       else
-                               parent = path->nodes[*level + 1];
+                       ret = walk_up_proc(trans, root, path, wc);
+                       if (ret > 0)
+                               return 0;
 
-                       clean_tree_block(trans, root, path->nodes[i]);
-                       ret = btrfs_free_extent(trans, root,
-                                               path->nodes[i]->start,
-                                               path->nodes[i]->len,
-                                               parent->start,
-                                               btrfs_header_owner(parent),
-                                               *level, 0);
-                       BUG_ON(ret);
-                       if (path->locks[*level]) {
-                               btrfs_tree_unlock(path->nodes[i]);
-                               path->locks[i] = 0;
+                       if (path->locks[level]) {
+                               btrfs_tree_unlock(path->nodes[level]);
+                               path->locks[level] = 0;
                        }
-                       free_extent_buffer(path->nodes[i]);
-                       path->nodes[i] = NULL;
-                       *level = i + 1;
+                       free_extent_buffer(path->nodes[level]);
+                       path->nodes[level] = NULL;
+                       level++;
                }
        }
        return 1;
 }
 
 /*
- * drop the reference count on the tree rooted at 'snap'.  This traverses
- * the tree freeing any blocks that have a ref count of zero after being
- * decremented.
+ * drop a subvolume tree.
+ *
+ * this function traverses the tree freeing any blocks that only
+ * referenced by the tree.
+ *
+ * when a shared tree block is found. this function decreases its
+ * reference count by one. if update_ref is true, this function
+ * also make sure backrefs for the shared block and all lower level
+ * blocks are properly updated.
  */
-int btrfs_drop_snapshot(struct btrfs_trans_handle *trans, struct btrfs_root
-                       *root)
+int btrfs_drop_snapshot(struct btrfs_root *root, int update_ref)
 {
-       int ret = 0;
-       int wret;
-       int level;
        struct btrfs_path *path;
-       int update_count;
+       struct btrfs_trans_handle *trans;
+       struct btrfs_root *tree_root = root->fs_info->tree_root;
        struct btrfs_root_item *root_item = &root->root_item;
+       struct walk_control *wc;
+       struct btrfs_key key;
+       int err = 0;
+       int ret;
+       int level;
 
        path = btrfs_alloc_path();
        BUG_ON(!path);
 
-       level = btrfs_header_level(root->node);
+       wc = kzalloc(sizeof(*wc), GFP_NOFS);
+       BUG_ON(!wc);
+
+       trans = btrfs_start_transaction(tree_root, 1);
+
        if (btrfs_disk_key_objectid(&root_item->drop_progress) == 0) {
+               level = btrfs_header_level(root->node);
                path->nodes[level] = btrfs_lock_root_node(root);
                btrfs_set_lock_blocking(path->nodes[level]);
                path->slots[level] = 0;
                path->locks[level] = 1;
+               memset(&wc->update_progress, 0,
+                      sizeof(wc->update_progress));
        } else {
-               struct btrfs_key key;
-               struct btrfs_disk_key found_key;
-               struct extent_buffer *node;
-
                btrfs_disk_key_to_cpu(&key, &root_item->drop_progress);
+               memcpy(&wc->update_progress, &key,
+                      sizeof(wc->update_progress));
+
                level = root_item->drop_level;
+               BUG_ON(level == 0);
                path->lowest_level = level;
-               wret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
-               if (wret < 0) {
-                       ret = wret;
+               ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
+               path->lowest_level = 0;
+               if (ret < 0) {
+                       err = ret;
                        goto out;
                }
-               node = path->nodes[level];
-               btrfs_node_key(node, &found_key, path->slots[level]);
-               WARN_ON(memcmp(&found_key, &root_item->drop_progress,
-                              sizeof(found_key)));
+               btrfs_node_key_to_cpu(path->nodes[level], &key,
+                                     path->slots[level]);
+               WARN_ON(memcmp(&key, &wc->update_progress, sizeof(key)));
+
                /*
                 * unlock our path, this is safe because only this
                 * function is allowed to delete this snapshot
                 */
                btrfs_unlock_up_safe(path, 0);
+
+               level = btrfs_header_level(root->node);
+               while (1) {
+                       btrfs_tree_lock(path->nodes[level]);
+                       btrfs_set_lock_blocking(path->nodes[level]);
+
+                       ret = btrfs_lookup_extent_info(trans, root,
+                                               path->nodes[level]->start,
+                                               path->nodes[level]->len,
+                                               &wc->refs[level],
+                                               &wc->flags[level]);
+                       BUG_ON(ret);
+                       BUG_ON(wc->refs[level] == 0);
+
+                       if (level == root_item->drop_level)
+                               break;
+
+                       btrfs_tree_unlock(path->nodes[level]);
+                       WARN_ON(wc->refs[level] != 1);
+                       level--;
+               }
        }
+
+       wc->level = level;
+       wc->shared_level = -1;
+       wc->stage = DROP_REFERENCE;
+       wc->update_ref = update_ref;
+       wc->keep_locks = 0;
+
        while (1) {
-               unsigned long update;
-               wret = walk_down_tree(trans, root, path, &level);
-               if (wret > 0)
+               ret = walk_down_tree(trans, root, path, wc);
+               if (ret < 0) {
+                       err = ret;
                        break;
-               if (wret < 0)
-                       ret = wret;
+               }
 
-               wret = walk_up_tree(trans, root, path, &level,
-                                   BTRFS_MAX_LEVEL);
-               if (wret > 0)
+               ret = walk_up_tree(trans, root, path, wc, BTRFS_MAX_LEVEL);
+               if (ret < 0) {
+                       err = ret;
                        break;
-               if (wret < 0)
-                       ret = wret;
-               if (trans->transaction->in_commit ||
-                   trans->transaction->delayed_refs.flushing) {
-                       ret = -EAGAIN;
+               }
+
+               if (ret > 0) {
+                       BUG_ON(wc->stage != DROP_REFERENCE);
                        break;
                }
-               for (update_count = 0; update_count < 16; update_count++) {
+
+               if (wc->stage == DROP_REFERENCE) {
+                       level = wc->level;
+                       btrfs_node_key(path->nodes[level],
+                                      &root_item->drop_progress,
+                                      path->slots[level]);
+                       root_item->drop_level = level;
+               }
+
+               BUG_ON(wc->level == 0);
+               if (trans->transaction->in_commit ||
+                   trans->transaction->delayed_refs.flushing) {
+                       ret = btrfs_update_root(trans, tree_root,
+                                               &root->root_key,
+                                               root_item);
+                       BUG_ON(ret);
+
+                       btrfs_end_transaction(trans, tree_root);
+                       trans = btrfs_start_transaction(tree_root, 1);
+               } else {
+                       unsigned long update;
                        update = trans->delayed_ref_updates;
                        trans->delayed_ref_updates = 0;
                        if (update)
-                               btrfs_run_delayed_refs(trans, root, update);
-                       else
-                               break;
+                               btrfs_run_delayed_refs(trans, tree_root,
+                                                      update);
                }
        }
+       btrfs_release_path(root, path);
+       BUG_ON(err);
+
+       ret = btrfs_del_root(trans, tree_root, &root->root_key);
+       BUG_ON(ret);
+
+       free_extent_buffer(root->node);
+       free_extent_buffer(root->commit_root);
+       kfree(root);
 out:
+       btrfs_end_transaction(trans, tree_root);
+       kfree(wc);
        btrfs_free_path(path);
-       return ret;
+       return err;
 }
 
+/*
+ * drop subtree rooted at tree block 'node'.
+ *
+ * NOTE: this function will unlock and release tree block 'node'
+ */
 int btrfs_drop_subtree(struct btrfs_trans_handle *trans,
                        struct btrfs_root *root,
                        struct extent_buffer *node,
                        struct extent_buffer *parent)
 {
        struct btrfs_path *path;
+       struct walk_control *wc;
        int level;
        int parent_level;
        int ret = 0;
        int wret;
 
+       BUG_ON(root->root_key.objectid != BTRFS_TREE_RELOC_OBJECTID);
+
        path = btrfs_alloc_path();
        BUG_ON(!path);
 
+       wc = kzalloc(sizeof(*wc), GFP_NOFS);
+       BUG_ON(!wc);
+
        btrfs_assert_tree_locked(parent);
        parent_level = btrfs_header_level(parent);
        extent_buffer_get(parent);
@@ -4817,24 +5024,33 @@ int btrfs_drop_subtree(struct btrfs_trans_handle *trans,
 
        btrfs_assert_tree_locked(node);
        level = btrfs_header_level(node);
-       extent_buffer_get(node);
        path->nodes[level] = node;
        path->slots[level] = 0;
+       path->locks[level] = 1;
+
+       wc->refs[parent_level] = 1;
+       wc->flags[parent_level] = BTRFS_BLOCK_FLAG_FULL_BACKREF;
+       wc->level = level;
+       wc->shared_level = -1;
+       wc->stage = DROP_REFERENCE;
+       wc->update_ref = 0;
+       wc->keep_locks = 1;
 
        while (1) {
-               wret = walk_down_tree(trans, root, path, &level);
-               if (wret < 0)
+               wret = walk_down_tree(trans, root, path, wc);
+               if (wret < 0) {
                        ret = wret;
-               if (wret != 0)
                        break;
+               }
 
-               wret = walk_up_tree(trans, root, path, &level, parent_level);
+               wret = walk_up_tree(trans, root, path, wc, parent_level);
                if (wret < 0)
                        ret = wret;
                if (wret != 0)
                        break;
        }
 
+       kfree(wc);
        btrfs_free_path(path);
        return ret;
 }
index 126477e..7c3cd24 100644 (file)
@@ -151,7 +151,10 @@ static noinline int dirty_and_release_pages(struct btrfs_trans_handle *trans,
        }
        if (end_pos > isize) {
                i_size_write(inode, end_pos);
-               btrfs_update_inode(trans, root, inode);
+               /* we've only changed i_size in ram, and we haven't updated
+                * the disk i_size.  There is no need to log the inode
+                * at this time.
+                */
        }
        err = btrfs_end_transaction(trans, root);
 out_unlock:
index dbe1aab..7ffa3d3 100644 (file)
@@ -3580,12 +3580,6 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
                owner = 1;
        BTRFS_I(inode)->block_group =
                        btrfs_find_block_group(root, 0, alloc_hint, owner);
-       if ((mode & S_IFREG)) {
-               if (btrfs_test_opt(root, NODATASUM))
-                       BTRFS_I(inode)->flags |= BTRFS_INODE_NODATASUM;
-               if (btrfs_test_opt(root, NODATACOW))
-                       BTRFS_I(inode)->flags |= BTRFS_INODE_NODATACOW;
-       }
 
        key[0].objectid = objectid;
        btrfs_set_key_type(&key[0], BTRFS_INODE_ITEM_KEY);
@@ -3640,6 +3634,13 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
 
        btrfs_inherit_iflags(inode, dir);
 
+       if ((mode & S_IFREG)) {
+               if (btrfs_test_opt(root, NODATASUM))
+                       BTRFS_I(inode)->flags |= BTRFS_INODE_NODATASUM;
+               if (btrfs_test_opt(root, NODATACOW))
+                       BTRFS_I(inode)->flags |= BTRFS_INODE_NODATACOW;
+       }
+
        insert_inode_hash(inode);
        inode_tree_add(inode);
        return inode;
@@ -5082,6 +5083,7 @@ static long btrfs_fallocate(struct inode *inode, int mode,
        u64 mask = BTRFS_I(inode)->root->sectorsize - 1;
        struct extent_map *em;
        struct btrfs_trans_handle *trans;
+       struct btrfs_root *root;
        int ret;
 
        alloc_start = offset & ~mask;
@@ -5100,6 +5102,13 @@ static long btrfs_fallocate(struct inode *inode, int mode,
                        goto out;
        }
 
+       root = BTRFS_I(inode)->root;
+
+       ret = btrfs_check_data_free_space(root, inode,
+                                         alloc_end - alloc_start);
+       if (ret)
+               goto out;
+
        locked_end = alloc_end - 1;
        while (1) {
                struct btrfs_ordered_extent *ordered;
@@ -5107,7 +5116,7 @@ static long btrfs_fallocate(struct inode *inode, int mode,
                trans = btrfs_start_transaction(BTRFS_I(inode)->root, 1);
                if (!trans) {
                        ret = -EIO;
-                       goto out;
+                       goto out_free;
                }
 
                /* the extent lock is ordered inside the running
@@ -5168,6 +5177,8 @@ static long btrfs_fallocate(struct inode *inode, int mode,
                      GFP_NOFS);
 
        btrfs_end_transaction(trans, BTRFS_I(inode)->root);
+out_free:
+       btrfs_free_reserved_data_space(root, inode, alloc_end - alloc_start);
 out:
        mutex_unlock(&inode->i_mutex);
        return ret;
index eff18f5..9f4db84 100644 (file)
@@ -1028,7 +1028,8 @@ static long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
                                                struct btrfs_file_extent_item);
                        comp = btrfs_file_extent_compression(leaf, extent);
                        type = btrfs_file_extent_type(leaf, extent);
-                       if (type == BTRFS_FILE_EXTENT_REG) {
+                       if (type == BTRFS_FILE_EXTENT_REG ||
+                           type == BTRFS_FILE_EXTENT_PREALLOC) {
                                disko = btrfs_file_extent_disk_bytenr(leaf,
                                                                      extent);
                                diskl = btrfs_file_extent_disk_num_bytes(leaf,
@@ -1051,7 +1052,8 @@ static long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
                        new_key.objectid = inode->i_ino;
                        new_key.offset = key.offset + destoff - off;
 
-                       if (type == BTRFS_FILE_EXTENT_REG) {
+                       if (type == BTRFS_FILE_EXTENT_REG ||
+                           type == BTRFS_FILE_EXTENT_PREALLOC) {
                                ret = btrfs_insert_empty_item(trans, root, path,
                                                              &new_key, size);
                                if (ret)
index b23dc20..0083979 100644 (file)
@@ -1788,7 +1788,7 @@ static void merge_func(struct btrfs_work *work)
                btrfs_end_transaction(trans, root);
        }
 
-       btrfs_drop_dead_root(reloc_root);
+       btrfs_drop_snapshot(reloc_root, 0);
 
        if (atomic_dec_and_test(async->num_pending))
                complete(async->done);
@@ -2075,9 +2075,6 @@ static int do_relocation(struct btrfs_trans_handle *trans,
 
                        ret = btrfs_drop_subtree(trans, root, eb, upper->eb);
                        BUG_ON(ret);
-
-                       btrfs_tree_unlock(eb);
-                       free_extent_buffer(eb);
                }
                if (!lowest) {
                        btrfs_tree_unlock(upper->eb);
index 4e83457..2dbf1c1 100644 (file)
@@ -593,6 +593,7 @@ int btrfs_defrag_root(struct btrfs_root *root, int cacheonly)
        return 0;
 }
 
+#if 0
 /*
  * when dropping snapshots, we generate a ton of delayed refs, and it makes
  * sense not to join the transaction while it is trying to flush the current
@@ -681,6 +682,7 @@ int btrfs_drop_dead_root(struct btrfs_root *root)
        btrfs_btree_balance_dirty(tree_root, nr);
        return ret;
 }
+#endif
 
 /*
  * new snapshots need to be created at a very specific time in the
@@ -1081,7 +1083,7 @@ int btrfs_clean_old_snapshots(struct btrfs_root *root)
        while (!list_empty(&list)) {
                root = list_entry(list.next, struct btrfs_root, root_list);
                list_del_init(&root->root_list);
-               btrfs_drop_dead_root(root);
+               btrfs_drop_snapshot(root, 0);
        }
        return 0;
 }
index b486898..3a9b7a5 100644 (file)
@@ -5,7 +5,7 @@ client generated ones by default (mount option "serverino" turned
 on by default if server supports it).  Add forceuid and forcegid
 mount options (so that when negotiating unix extensions specifying
 which uid mounted does not immediately force the server's reported
-uids to be overridden).
+uids to be overridden).  Add support for scope moutn parm.
 
 Version 1.58
 ------------
index 1b09f16..20692fb 100644 (file)
@@ -49,6 +49,7 @@
 #define ASN1_OJI       6       /* Object Identifier  */
 #define ASN1_OJD       7       /* Object Description */
 #define ASN1_EXT       8       /* External */
+#define ASN1_ENUM      10      /* Enumerated */
 #define ASN1_SEQ       16      /* Sequence */
 #define ASN1_SET       17      /* Set */
 #define ASN1_NUMSTR    18      /* Numerical String */
 #define SPNEGO_OID_LEN 7
 #define NTLMSSP_OID_LEN  10
 #define KRB5_OID_LEN  7
+#define KRB5U2U_OID_LEN  8
 #define MSKRB5_OID_LEN  7
 static unsigned long SPNEGO_OID[7] = { 1, 3, 6, 1, 5, 5, 2 };
 static unsigned long NTLMSSP_OID[10] = { 1, 3, 6, 1, 4, 1, 311, 2, 2, 10 };
 static unsigned long KRB5_OID[7] = { 1, 2, 840, 113554, 1, 2, 2 };
+static unsigned long KRB5U2U_OID[8] = { 1, 2, 840, 113554, 1, 2, 2, 3 };
 static unsigned long MSKRB5_OID[7] = { 1, 2, 840, 48018, 1, 2, 2 };
 
 /*
@@ -122,6 +125,28 @@ asn1_octet_decode(struct asn1_ctx *ctx, unsigned char *ch)
        return 1;
 }
 
+#if 0 /* will be needed later by spnego decoding/encoding of ntlmssp */
+static unsigned char
+asn1_enum_decode(struct asn1_ctx *ctx, __le32 *val)
+{
+       unsigned char ch;
+
+       if (ctx->pointer >= ctx->end) {
+               ctx->error = ASN1_ERR_DEC_EMPTY;
+               return 0;
+       }
+
+       ch = *(ctx->pointer)++; /* ch has 0xa, ptr points to lenght octet */
+       if ((ch) == ASN1_ENUM)  /* if ch value is ENUM, 0xa */
+               *val = *(++(ctx->pointer)); /* value has enum value */
+       else
+               return 0;
+
+       ctx->pointer++;
+       return 1;
+}
+#endif
+
 static unsigned char
 asn1_tag_decode(struct asn1_ctx *ctx, unsigned int *tag)
 {
@@ -476,10 +501,9 @@ decode_negTokenInit(unsigned char *security_blob, int length,
        unsigned int cls, con, tag, oidlen, rc;
        bool use_ntlmssp = false;
        bool use_kerberos = false;
+       bool use_kerberosu2u = false;
        bool use_mskerberos = false;
 
-       *secType = NTLM; /* BB eventually make Kerberos or NLTMSSP the default*/
-
        /* cifs_dump_mem(" Received SecBlob ", security_blob, length); */
 
        asn1_open(&ctx, security_blob, length);
@@ -515,6 +539,7 @@ decode_negTokenInit(unsigned char *security_blob, int length,
                return 0;
        }
 
+       /* SPNEGO */
        if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
                cFYI(1, ("Error decoding negTokenInit"));
                return 0;
@@ -526,6 +551,7 @@ decode_negTokenInit(unsigned char *security_blob, int length,
                return 0;
        }
 
+       /* negTokenInit */
        if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
                cFYI(1, ("Error decoding negTokenInit"));
                return 0;
@@ -537,6 +563,7 @@ decode_negTokenInit(unsigned char *security_blob, int length,
                return 0;
        }
 
+       /* sequence */
        if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
                cFYI(1, ("Error decoding 2nd part of negTokenInit"));
                return 0;
@@ -548,6 +575,7 @@ decode_negTokenInit(unsigned char *security_blob, int length,
                return 0;
        }
 
+       /* sequence of */
        if (asn1_header_decode
            (&ctx, &sequence_end, &cls, &con, &tag) == 0) {
                cFYI(1, ("Error decoding 2nd part of negTokenInit"));
@@ -560,6 +588,7 @@ decode_negTokenInit(unsigned char *security_blob, int length,
                return 0;
        }
 
+       /* list of security mechanisms */
        while (!asn1_eoc_decode(&ctx, sequence_end)) {
                rc = asn1_header_decode(&ctx, &end, &cls, &con, &tag);
                if (!rc) {
@@ -576,11 +605,15 @@ decode_negTokenInit(unsigned char *security_blob, int length,
 
                                if (compare_oid(oid, oidlen, MSKRB5_OID,
                                                MSKRB5_OID_LEN) &&
-                                               !use_kerberos)
+                                               !use_mskerberos)
                                        use_mskerberos = true;
+                               else if (compare_oid(oid, oidlen, KRB5U2U_OID,
+                                                    KRB5U2U_OID_LEN) &&
+                                                    !use_kerberosu2u)
+                                       use_kerberosu2u = true;
                                else if (compare_oid(oid, oidlen, KRB5_OID,
                                                     KRB5_OID_LEN) &&
-                                                    !use_mskerberos)
+                                                    !use_kerberos)
                                        use_kerberos = true;
                                else if (compare_oid(oid, oidlen, NTLMSSP_OID,
                                                     NTLMSSP_OID_LEN))
@@ -593,7 +626,12 @@ decode_negTokenInit(unsigned char *security_blob, int length,
                }
        }
 
+       /* mechlistMIC */
        if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
+               /* Check if we have reached the end of the blob, but with
+                  no mechListMic (e.g. NTLMSSP instead of KRB5) */
+               if (ctx.error == ASN1_ERR_DEC_EMPTY)
+                       goto decode_negtoken_exit;
                cFYI(1, ("Error decoding last part negTokenInit exit3"));
                return 0;
        } else if ((cls != ASN1_CTX) || (con != ASN1_CON)) {
@@ -602,6 +640,8 @@ decode_negTokenInit(unsigned char *security_blob, int length,
                         cls, con, tag, end, *end));
                return 0;
        }
+
+       /* sequence */
        if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
                cFYI(1, ("Error decoding last part negTokenInit exit5"));
                return 0;
@@ -611,6 +651,7 @@ decode_negTokenInit(unsigned char *security_blob, int length,
                        cls, con, tag, end, *end));
        }
 
+       /* sequence of */
        if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
                cFYI(1, ("Error decoding last part negTokenInit exit 7"));
                return 0;
@@ -619,6 +660,8 @@ decode_negTokenInit(unsigned char *security_blob, int length,
                         cls, con, tag, end, *end));
                return 0;
        }
+
+       /* general string */
        if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
                cFYI(1, ("Error decoding last part negTokenInit exit9"));
                return 0;
@@ -630,13 +673,13 @@ decode_negTokenInit(unsigned char *security_blob, int length,
        }
        cFYI(1, ("Need to call asn1_octets_decode() function for %s",
                 ctx.pointer)); /* is this UTF-8 or ASCII? */
-
+decode_negtoken_exit:
        if (use_kerberos)
                *secType = Kerberos;
        else if (use_mskerberos)
                *secType = MSKerberos;
        else if (use_ntlmssp)
-               *secType = NTLMSSP;
+               *secType = RawNTLMSSP;
 
        return 1;
 }
index 0d92114..9f669f9 100644 (file)
@@ -333,6 +333,27 @@ cifs_destroy_inode(struct inode *inode)
        kmem_cache_free(cifs_inode_cachep, CIFS_I(inode));
 }
 
+static void
+cifs_show_address(struct seq_file *s, struct TCP_Server_Info *server)
+{
+       seq_printf(s, ",addr=");
+
+       switch (server->addr.sockAddr.sin_family) {
+       case AF_INET:
+               seq_printf(s, "%pI4", &server->addr.sockAddr.sin_addr.s_addr);
+               break;
+       case AF_INET6:
+               seq_printf(s, "%pI6",
+                          &server->addr.sockAddr6.sin6_addr.s6_addr);
+               if (server->addr.sockAddr6.sin6_scope_id)
+                       seq_printf(s, "%%%u",
+                                  server->addr.sockAddr6.sin6_scope_id);
+               break;
+       default:
+               seq_printf(s, "(unknown)");
+       }
+}
+
 /*
  * cifs_show_options() is for displaying mount options in /proc/mounts.
  * Not all settable options are displayed but most of the important
@@ -343,83 +364,64 @@ cifs_show_options(struct seq_file *s, struct vfsmount *m)
 {
        struct cifs_sb_info *cifs_sb;
        struct cifsTconInfo *tcon;
-       struct TCP_Server_Info *server;
 
        cifs_sb = CIFS_SB(m->mnt_sb);
+       tcon = cifs_sb->tcon;
 
-       if (cifs_sb) {
-               tcon = cifs_sb->tcon;
-               if (tcon) {
-                       seq_printf(s, ",unc=%s", cifs_sb->tcon->treeName);
-                       if (tcon->ses) {
-                               if (tcon->ses->userName)
-                                       seq_printf(s, ",username=%s",
-                                          tcon->ses->userName);
-                               if (tcon->ses->domainName)
-                                       seq_printf(s, ",domain=%s",
-                                          tcon->ses->domainName);
-                               server = tcon->ses->server;
-                               if (server) {
-                                       seq_printf(s, ",addr=");
-                                       switch (server->addr.sockAddr6.
-                                               sin6_family) {
-                                       case AF_INET6:
-                                               seq_printf(s, "%pI6",
-                                                          &server->addr.sockAddr6.sin6_addr);
-                                               break;
-                                       case AF_INET:
-                                               seq_printf(s, "%pI4",
-                                                          &server->addr.sockAddr.sin_addr.s_addr);
-                                               break;
-                                       }
-                               }
-                       }
-                       if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID) ||
-                          !(tcon->unix_ext))
-                               seq_printf(s, ",uid=%d", cifs_sb->mnt_uid);
-                       if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID) ||
-                          !(tcon->unix_ext))
-                               seq_printf(s, ",gid=%d", cifs_sb->mnt_gid);
-                       if (!tcon->unix_ext) {
-                               seq_printf(s, ",file_mode=0%o,dir_mode=0%o",
+       seq_printf(s, ",unc=%s", cifs_sb->tcon->treeName);
+       if (tcon->ses->userName)
+               seq_printf(s, ",username=%s", tcon->ses->userName);
+       if (tcon->ses->domainName)
+               seq_printf(s, ",domain=%s", tcon->ses->domainName);
+
+       seq_printf(s, ",uid=%d", cifs_sb->mnt_uid);
+       if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID)
+               seq_printf(s, ",forceuid");
+
+       seq_printf(s, ",gid=%d", cifs_sb->mnt_gid);
+       if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID)
+               seq_printf(s, ",forcegid");
+
+       cifs_show_address(s, tcon->ses->server);
+
+       if (!tcon->unix_ext)
+               seq_printf(s, ",file_mode=0%o,dir_mode=0%o",
                                           cifs_sb->mnt_file_mode,
                                           cifs_sb->mnt_dir_mode);
-                       }
-                       if (tcon->seal)
-                               seq_printf(s, ",seal");
-                       if (tcon->nocase)
-                               seq_printf(s, ",nocase");
-                       if (tcon->retry)
-                               seq_printf(s, ",hard");
-               }
-               if (cifs_sb->prepath)
-                       seq_printf(s, ",prepath=%s", cifs_sb->prepath);
-               if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS)
-                       seq_printf(s, ",posixpaths");
-               if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID)
-                       seq_printf(s, ",setuids");
-               if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)
-                       seq_printf(s, ",serverino");
-               if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO)
-                       seq_printf(s, ",directio");
-               if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
-                       seq_printf(s, ",nouser_xattr");
-               if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR)
-                       seq_printf(s, ",mapchars");
-               if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL)
-                       seq_printf(s, ",sfu");
-               if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
-                       seq_printf(s, ",nobrl");
-               if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL)
-                       seq_printf(s, ",cifsacl");
-               if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)
-                       seq_printf(s, ",dynperm");
-               if (m->mnt_sb->s_flags & MS_POSIXACL)
-                       seq_printf(s, ",acl");
-
-               seq_printf(s, ",rsize=%d", cifs_sb->rsize);
-               seq_printf(s, ",wsize=%d", cifs_sb->wsize);
-       }
+       if (tcon->seal)
+               seq_printf(s, ",seal");
+       if (tcon->nocase)
+               seq_printf(s, ",nocase");
+       if (tcon->retry)
+               seq_printf(s, ",hard");
+       if (cifs_sb->prepath)
+               seq_printf(s, ",prepath=%s", cifs_sb->prepath);
+       if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS)
+               seq_printf(s, ",posixpaths");
+       if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID)
+               seq_printf(s, ",setuids");
+       if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)
+               seq_printf(s, ",serverino");
+       if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO)
+               seq_printf(s, ",directio");
+       if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
+               seq_printf(s, ",nouser_xattr");
+       if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR)
+               seq_printf(s, ",mapchars");
+       if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL)
+               seq_printf(s, ",sfu");
+       if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
+               seq_printf(s, ",nobrl");
+       if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL)
+               seq_printf(s, ",cifsacl");
+       if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)
+               seq_printf(s, ",dynperm");
+       if (m->mnt_sb->s_flags & MS_POSIXACL)
+               seq_printf(s, ",acl");
+
+       seq_printf(s, ",rsize=%d", cifs_sb->rsize);
+       seq_printf(s, ",wsize=%d", cifs_sb->wsize);
+
        return 0;
 }
 
@@ -535,9 +537,14 @@ static void cifs_umount_begin(struct super_block *sb)
        if (tcon == NULL)
                return;
 
-       lock_kernel();
        read_lock(&cifs_tcp_ses_lock);
-       if (tcon->tc_count == 1)
+       if ((tcon->tc_count > 1) || (tcon->tidStatus == CifsExiting)) {
+               /* we have other mounts to same share or we have
+                  already tried to force umount this and woken up
+                  all waiting network requests, nothing to do */
+               read_unlock(&cifs_tcp_ses_lock);
+               return;
+       } else if (tcon->tc_count == 1)
                tcon->tidStatus = CifsExiting;
        read_unlock(&cifs_tcp_ses_lock);
 
@@ -552,9 +559,7 @@ static void cifs_umount_begin(struct super_block *sb)
                wake_up_all(&tcon->ses->server->response_q);
                msleep(1);
        }
-/* BB FIXME - finish add checks for tidStatus BB */
 
-       unlock_kernel();
        return;
 }
 
index a61ab77..e1225e6 100644 (file)
@@ -83,7 +83,7 @@ enum securityEnum {
        NTLM,                   /* Legacy NTLM012 auth with NTLM hash */
        NTLMv2,                 /* Legacy NTLM auth with NTLMv2 hash */
        RawNTLMSSP,             /* NTLMSSP without SPNEGO, NTLMv2 hash */
-       NTLMSSP,                /* NTLMSSP via SPNEGO, NTLMv2 hash */
+/*     NTLMSSP, */ /* can use rawNTLMSSP instead of NTLMSSP via SPNEGO */
        Kerberos,               /* Kerberos via SPNEGO */
        MSKerberos,             /* MS Kerberos via SPNEGO */
 };
index f945232..c419416 100644 (file)
@@ -74,7 +74,7 @@ extern unsigned int smbCalcSize(struct smb_hdr *ptr);
 extern unsigned int smbCalcSize_LE(struct smb_hdr *ptr);
 extern int decode_negTokenInit(unsigned char *security_blob, int length,
                        enum securityEnum *secType);
-extern int cifs_inet_pton(const int, const char *source, void *dst);
+extern int cifs_convert_address(char *src, void *dst);
 extern int map_smb_to_linux_error(struct smb_hdr *smb, int logErr);
 extern void header_assemble(struct smb_hdr *, char /* command */ ,
                            const struct cifsTconInfo *, int /* length of
index b84c61d..61007c6 100644 (file)
@@ -594,7 +594,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
        else if (secFlags & CIFSSEC_MAY_KRB5)
                server->secType = Kerberos;
        else if (secFlags & CIFSSEC_MAY_NTLMSSP)
-               server->secType = NTLMSSP;
+               server->secType = RawNTLMSSP;
        else if (secFlags & CIFSSEC_MAY_LANMAN)
                server->secType = LANMAN;
 /* #ifdef CONFIG_CIFS_EXPERIMENTAL
@@ -729,7 +729,7 @@ CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
         * the tcon is no longer on the list, so no need to take lock before
         * checking this.
         */
-       if (tcon->need_reconnect)
+       if ((tcon->need_reconnect) || (tcon->ses->need_reconnect))
                return 0;
 
        rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
index 97f4311..e16d759 100644 (file)
@@ -70,7 +70,6 @@ struct smb_vol {
        mode_t file_mode;
        mode_t dir_mode;
        unsigned secFlg;
-       bool rw:1;
        bool retry:1;
        bool intr:1;
        bool setuids:1;
@@ -832,7 +831,6 @@ cifs_parse_mount_options(char *options, const char *devname,
        vol->dir_mode = vol->file_mode = S_IRUGO | S_IXUGO | S_IWUSR;
 
        /* vol->retry default is 0 (i.e. "soft" limited retry not hard retry) */
-       vol->rw = true;
        /* default is always to request posix paths. */
        vol->posix_paths = 1;
        /* default to using server inode numbers where available */
@@ -1199,7 +1197,9 @@ cifs_parse_mount_options(char *options, const char *devname,
                } else if (strnicmp(data, "guest", 5) == 0) {
                        /* ignore */
                } else if (strnicmp(data, "rw", 2) == 0) {
-                       vol->rw = true;
+                       /* ignore */
+               } else if (strnicmp(data, "ro", 2) == 0) {
+                       /* ignore */
                } else if (strnicmp(data, "noblocksend", 11) == 0) {
                        vol->noblocksnd = 1;
                } else if (strnicmp(data, "noautotune", 10) == 0) {
@@ -1218,8 +1218,6 @@ cifs_parse_mount_options(char *options, const char *devname,
                            parse these options again and set anything and it
                            is ok to just ignore them */
                        continue;
-               } else if (strnicmp(data, "ro", 2) == 0) {
-                       vol->rw = false;
                } else if (strnicmp(data, "hard", 4) == 0) {
                        vol->retry = 1;
                } else if (strnicmp(data, "soft", 4) == 0) {
@@ -1386,8 +1384,10 @@ cifs_find_tcp_session(struct sockaddr_storage *addr)
                     server->addr.sockAddr.sin_addr.s_addr))
                        continue;
                else if (addr->ss_family == AF_INET6 &&
-                        !ipv6_addr_equal(&server->addr.sockAddr6.sin6_addr,
-                                         &addr6->sin6_addr))
+                        (!ipv6_addr_equal(&server->addr.sockAddr6.sin6_addr,
+                                          &addr6->sin6_addr) ||
+                         server->addr.sockAddr6.sin6_scope_id !=
+                                          addr6->sin6_scope_id))
                        continue;
 
                ++server->srv_count;
@@ -1433,28 +1433,15 @@ cifs_get_tcp_session(struct smb_vol *volume_info)
 
        memset(&addr, 0, sizeof(struct sockaddr_storage));
 
-       if (volume_info->UNCip && volume_info->UNC) {
-               rc = cifs_inet_pton(AF_INET, volume_info->UNCip,
-                                   &sin_server->sin_addr.s_addr);
-
-               if (rc <= 0) {
-                       /* not ipv4 address, try ipv6 */
-                       rc = cifs_inet_pton(AF_INET6, volume_info->UNCip,
-                                           &sin_server6->sin6_addr.in6_u);
-                       if (rc > 0)
-                               addr.ss_family = AF_INET6;
-               } else {
-                       addr.ss_family = AF_INET;
-               }
+       cFYI(1, ("UNC: %s ip: %s", volume_info->UNC, volume_info->UNCip));
 
-               if (rc <= 0) {
+       if (volume_info->UNCip && volume_info->UNC) {
+               rc = cifs_convert_address(volume_info->UNCip, &addr);
+               if (!rc) {
                        /* we failed translating address */
                        rc = -EINVAL;
                        goto out_err;
                }
-
-               cFYI(1, ("UNC: %s ip: %s", volume_info->UNC,
-                        volume_info->UNCip));
        } else if (volume_info->UNCip) {
                /* BB using ip addr as tcp_ses name to connect to the
                   DFS root below */
@@ -1513,14 +1500,14 @@ cifs_get_tcp_session(struct smb_vol *volume_info)
                cFYI(1, ("attempting ipv6 connect"));
                /* BB should we allow ipv6 on port 139? */
                /* other OS never observed in Wild doing 139 with v6 */
+               sin_server6->sin6_port = htons(volume_info->port);
                memcpy(&tcp_ses->addr.sockAddr6, sin_server6,
                        sizeof(struct sockaddr_in6));
-               sin_server6->sin6_port = htons(volume_info->port);
                rc = ipv6_connect(tcp_ses);
        } else {
+               sin_server->sin_port = htons(volume_info->port);
                memcpy(&tcp_ses->addr.sockAddr, sin_server,
                        sizeof(struct sockaddr_in));
-               sin_server->sin_port = htons(volume_info->port);
                rc = ipv4_connect(tcp_ses);
        }
        if (rc < 0) {
index 3758965..7dc6b74 100644 (file)
@@ -307,8 +307,9 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
 
        full_path = build_path_from_dentry(direntry);
        if (full_path == NULL) {
+               rc = -ENOMEM;
                FreeXid(xid);
-               return -ENOMEM;
+               return rc;
        }
 
        if (oplockEnabled)
@@ -540,8 +541,9 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode,
                        buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
                        if (buf == NULL) {
                                kfree(full_path);
+                               rc = -ENOMEM;
                                FreeXid(xid);
-                               return -ENOMEM;
+                               return rc;
                        }
 
                        rc = CIFSSMBOpen(xid, pTcon, full_path,
index df4a306..8794814 100644 (file)
  *             0 - name is not IP
  */
 static int
-is_ip(const char *name)
+is_ip(char *name)
 {
-       int rc;
-       struct sockaddr_in sin_server;
-       struct sockaddr_in6 sin_server6;
-
-       rc = cifs_inet_pton(AF_INET, name,
-                       &sin_server.sin_addr.s_addr);
-
-       if (rc <= 0) {
-               /* not ipv4 address, try ipv6 */
-               rc = cifs_inet_pton(AF_INET6, name,
-                               &sin_server6.sin6_addr.in6_u);
-               if (rc > 0)
-                       return 1;
-       } else {
-               return 1;
-       }
-       /* we failed translating address */
-       return 0;
+       struct sockaddr_storage ss;
+
+       return cifs_convert_address(name, &ss);
 }
 
 static int
@@ -72,7 +57,7 @@ dns_resolver_instantiate(struct key *key, const void *data,
        ip[datalen] = '\0';
 
        /* make sure this looks like an address */
-       if (!is_ip((const char *) ip)) {
+       if (!is_ip(ip)) {
                kfree(ip);
                return -EINVAL;
        }
index 0686684..97ce4bf 100644 (file)
@@ -300,14 +300,16 @@ int cifs_open(struct inode *inode, struct file *file)
        pCifsInode = CIFS_I(file->f_path.dentry->d_inode);
        pCifsFile = cifs_fill_filedata(file);
        if (pCifsFile) {
+               rc = 0;
                FreeXid(xid);
-               return 0;
+               return rc;
        }
 
        full_path = build_path_from_dentry(file->f_path.dentry);
        if (full_path == NULL) {
+               rc = -ENOMEM;
                FreeXid(xid);
-               return -ENOMEM;
+               return rc;
        }
 
        cFYI(1, ("inode = 0x%p file flags are 0x%x for %s",
@@ -491,11 +493,12 @@ static int cifs_reopen_file(struct file *file, bool can_flush)
                return -EBADF;
 
        xid = GetXid();
-       mutex_unlock(&pCifsFile->fh_mutex);
+       mutex_lock(&pCifsFile->fh_mutex);
        if (!pCifsFile->invalidHandle) {
-               mutex_lock(&pCifsFile->fh_mutex);
+               mutex_unlock(&pCifsFile->fh_mutex);
+               rc = 0;
                FreeXid(xid);
-               return 0;
+               return rc;
        }
 
        if (file->f_path.dentry == NULL) {
@@ -524,7 +527,7 @@ static int cifs_reopen_file(struct file *file, bool can_flush)
        if (full_path == NULL) {
                rc = -ENOMEM;
 reopen_error_exit:
-               mutex_lock(&pCifsFile->fh_mutex);
+               mutex_unlock(&pCifsFile->fh_mutex);
                FreeXid(xid);
                return rc;
        }
@@ -566,14 +569,14 @@ reopen_error_exit:
                         cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
                                CIFS_MOUNT_MAP_SPECIAL_CHR);
        if (rc) {
-               mutex_lock(&pCifsFile->fh_mutex);
+               mutex_unlock(&pCifsFile->fh_mutex);
                cFYI(1, ("cifs_open returned 0x%x", rc));
                cFYI(1, ("oplock: %d", oplock));
        } else {
 reopen_success:
                pCifsFile->netfid = netfid;
                pCifsFile->invalidHandle = false;
-               mutex_lock(&pCifsFile->fh_mutex);
+               mutex_unlock(&pCifsFile->fh_mutex);
                pCifsInode = CIFS_I(inode);
                if (pCifsInode) {
                        if (can_flush) {
@@ -845,8 +848,9 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
        tcon = cifs_sb->tcon;
 
        if (file->private_data == NULL) {
+               rc = -EBADF;
                FreeXid(xid);
-               return -EBADF;
+               return rc;
        }
        netfid = ((struct cifsFileInfo *)file->private_data)->netfid;
 
@@ -1805,8 +1809,9 @@ ssize_t cifs_user_read(struct file *file, char __user *read_data,
        pTcon = cifs_sb->tcon;
 
        if (file->private_data == NULL) {
+               rc = -EBADF;
                FreeXid(xid);
-               return -EBADF;
+               return rc;
        }
        open_file = (struct cifsFileInfo *)file->private_data;
 
@@ -1885,8 +1890,9 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
        pTcon = cifs_sb->tcon;
 
        if (file->private_data == NULL) {
+               rc = -EBADF;
                FreeXid(xid);
-               return -EBADF;
+               return rc;
        }
        open_file = (struct cifsFileInfo *)file->private_data;
 
@@ -2019,8 +2025,9 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
 
        xid = GetXid();
        if (file->private_data == NULL) {
+               rc = -EBADF;
                FreeXid(xid);
-               return -EBADF;
+               return rc;
        }
        open_file = (struct cifsFileInfo *)file->private_data;
        cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
@@ -2185,8 +2192,9 @@ static int cifs_readpage(struct file *file, struct page *page)
        xid = GetXid();
 
        if (file->private_data == NULL) {
+               rc = -EBADF;
                FreeXid(xid);
-               return -EBADF;
+               return rc;
        }
 
        cFYI(1, ("readpage %p at offset %d 0x%x\n",
index fad882b..155c9e7 100644 (file)
@@ -988,8 +988,9 @@ int cifs_unlink(struct inode *dir, struct dentry *dentry)
         * sb->s_vfs_rename_mutex here */
        full_path = build_path_from_dentry(dentry);
        if (full_path == NULL) {
+               rc = -ENOMEM;
                FreeXid(xid);
-               return -ENOMEM;
+               return rc;
        }
 
        if ((tcon->ses->capabilities & CAP_UNIX) &&
@@ -1118,8 +1119,9 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
 
        full_path = build_path_from_dentry(direntry);
        if (full_path == NULL) {
+               rc = -ENOMEM;
                FreeXid(xid);
-               return -ENOMEM;
+               return rc;
        }
 
        if ((pTcon->ses->capabilities & CAP_UNIX) &&
@@ -1303,8 +1305,9 @@ int cifs_rmdir(struct inode *inode, struct dentry *direntry)
 
        full_path = build_path_from_dentry(direntry);
        if (full_path == NULL) {
+               rc = -ENOMEM;
                FreeXid(xid);
-               return -ENOMEM;
+               return rc;
        }
 
        rc = CIFSSMBRmDir(xid, pTcon, full_path, cifs_sb->local_nls,
@@ -1508,8 +1511,9 @@ int cifs_revalidate(struct dentry *direntry)
           since that would deadlock */
        full_path = build_path_from_dentry(direntry);
        if (full_path == NULL) {
+               rc = -ENOMEM;
                FreeXid(xid);
-               return -ENOMEM;
+               return rc;
        }
        cFYI(1, ("Revalidate: %s inode 0x%p count %d dentry: 0x%p d_time %ld "
                 "jiffies %ld", full_path, direntry->d_inode,
@@ -1911,8 +1915,9 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
 
        full_path = build_path_from_dentry(direntry);
        if (full_path == NULL) {
+               rc = -ENOMEM;
                FreeXid(xid);
-               return -ENOMEM;
+               return rc;
        }
 
        /*
index cd83c53..fc1e048 100644 (file)
@@ -172,8 +172,9 @@ cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname)
        full_path = build_path_from_dentry(direntry);
 
        if (full_path == NULL) {
+               rc = -ENOMEM;
                FreeXid(xid);
-               return -ENOMEM;
+               return rc;
        }
 
        cFYI(1, ("Full path: %s", full_path));
index 32d6baa..bd6d689 100644 (file)
@@ -133,10 +133,12 @@ static const struct smb_to_posix_error mapping_table_ERRHRD[] = {
        {0, 0}
 };
 
-/* Convert string containing dotted ip address to binary form */
-/* returns 0 if invalid address */
-
-int
+/*
+ * Convert a string containing text IPv4 or IPv6 address to binary form.
+ *
+ * Returns 0 on failure.
+ */
+static int
 cifs_inet_pton(const int address_family, const char *cp, void *dst)
 {
        int ret = 0;
@@ -153,6 +155,52 @@ cifs_inet_pton(const int address_family, const char *cp, void *dst)
        return ret;
 }
 
+/*
+ * Try to convert a string to an IPv4 address and then attempt to convert
+ * it to an IPv6 address if that fails. Set the family field if either
+ * succeeds. If it's an IPv6 address and it has a '%' sign in it, try to
+ * treat the part following it as a numeric sin6_scope_id.
+ *
+ * Returns 0 on failure.
+ */
+int
+cifs_convert_address(char *src, void *dst)
+{
+       int rc;
+       char *pct, *endp;
+       struct sockaddr_in *s4 = (struct sockaddr_in *) dst;
+       struct sockaddr_in6 *s6 = (struct sockaddr_in6 *) dst;
+
+       /* IPv4 address */
+       if (cifs_inet_pton(AF_INET, src, &s4->sin_addr.s_addr)) {
+               s4->sin_family = AF_INET;
+               return 1;
+       }
+
+       /* temporarily terminate string */
+       pct = strchr(src, '%');
+       if (pct)
+               *pct = '\0';
+
+       rc = cifs_inet_pton(AF_INET6, src, &s6->sin6_addr.s6_addr);
+
+       /* repair temp termination (if any) and make pct point to scopeid */
+       if (pct)
+               *pct++ = '%';
+
+       if (!rc)
+               return rc;
+
+       s6->sin6_family = AF_INET6;
+       if (pct) {
+               s6->sin6_scope_id = (u32) simple_strtoul(pct, &endp, 0);
+               if (!*pct || *endp)
+                       return 0;
+       }
+
+       return rc;
+}
+
 /*****************************************************************************
 convert a NT status code to a dos class/code
  *****************************************************************************/
index 897a052..7085a62 100644 (file)
@@ -802,7 +802,7 @@ ssetup_ntlmssp_authenticate:
 #endif /* CONFIG_CIFS_UPCALL */
        } else {
 #ifdef CONFIG_CIFS_EXPERIMENTAL
-               if ((experimEnabled > 1) && (type == RawNTLMSSP)) {
+               if (type == RawNTLMSSP) {
                        if ((pSMB->req.hdr.Flags2 & SMBFLG2_UNICODE) == 0) {
                                cERROR(1, ("NTLMSSP requires Unicode support"));
                                rc = -ENOSYS;
index e9527ee..a75afa3 100644 (file)
@@ -64,8 +64,9 @@ int cifs_removexattr(struct dentry *direntry, const char *ea_name)
 
        full_path = build_path_from_dentry(direntry);
        if (full_path == NULL) {
+               rc = -ENOMEM;
                FreeXid(xid);
-               return -ENOMEM;
+               return rc;
        }
        if (ea_name == NULL) {
                cFYI(1, ("Null xattr names not supported"));
@@ -118,8 +119,9 @@ int cifs_setxattr(struct dentry *direntry, const char *ea_name,
 
        full_path = build_path_from_dentry(direntry);
        if (full_path == NULL) {
+               rc = -ENOMEM;
                FreeXid(xid);
-               return -ENOMEM;
+               return rc;
        }
        /* return dos attributes as pseudo xattr */
        /* return alt name if available as pseudo attr */
@@ -225,8 +227,9 @@ ssize_t cifs_getxattr(struct dentry *direntry, const char *ea_name,
 
        full_path = build_path_from_dentry(direntry);
        if (full_path == NULL) {
+               rc = -ENOMEM;
                FreeXid(xid);
-               return -ENOMEM;
+               return rc;
        }
        /* return dos attributes as pseudo xattr */
        /* return alt name if available as pseudo attr */
@@ -351,8 +354,9 @@ ssize_t cifs_listxattr(struct dentry *direntry, char *data, size_t buf_size)
 
        full_path = build_path_from_dentry(direntry);
        if (full_path == NULL) {
+               rc = -ENOMEM;
                FreeXid(xid);
-               return -ENOMEM;
+               return rc;
        }
        /* return dos attributes as pseudo xattr */
        /* return alt name if available as pseudo attr */
index ccc9d62..55ea369 100644 (file)
@@ -63,7 +63,7 @@ static int send_data(struct sk_buff *skb)
                return rv;
        }
 
-       return genlmsg_unicast(skb, listener_nlpid);
+       return genlmsg_unicast(&init_net, skb, listener_nlpid);
 }
 
 static int user_cmd(struct sk_buff *skb, struct genl_info *info)
index 3f0e197..31d12de 100644 (file)
 #include <linux/list.h>
 #include <linux/spinlock.h>
 #include <linux/anon_inodes.h>
-#include <linux/eventfd.h>
 #include <linux/syscalls.h>
 #include <linux/module.h>
+#include <linux/kref.h>
+#include <linux/eventfd.h>
 
 struct eventfd_ctx {
+       struct kref kref;
        wait_queue_head_t wqh;
        /*
         * Every time that a write(2) is performed on an eventfd, the
         * value of the __u64 being written is added to "count" and a
         * wakeup is performed on "wqh". A read(2) will return the "count"
         * value to userspace, and will reset "count" to zero. The kernel
-        * size eventfd_signal() also, adds to the "count" counter and
+        * side eventfd_signal() also, adds to the "count" counter and
         * issue a wakeup.
         */
        __u64 count;
        unsigned int flags;
 };
 
-/*
- * Adds "n" to the eventfd counter "count". Returns "n" in case of
- * success, or a value lower then "n" in case of coutner overflow.
- * This function is supposed to be called by the kernel in paths
- * that do not allow sleeping. In this function we allow the counter
- * to reach the ULLONG_MAX value, and we signal this as overflow
- * condition by returining a POLLERR to poll(2).
+/**
+ * eventfd_signal - Adds @n to the eventfd counter.
+ * @ctx: [in] Pointer to the eventfd context.
+ * @n: [in] Value of the counter to be added to the eventfd internal counter.
+ *          The value cannot be negative.
+ *
+ * This function is supposed to be called by the kernel in paths that do not
+ * allow sleeping. In this function we allow the counter to reach the ULLONG_MAX
+ * value, and we signal this as overflow condition by returining a POLLERR
+ * to poll(2).
+ *
+ * Returns @n in case of success, a non-negative number lower than @n in case
+ * of overflow, or the following error codes:
+ *
+ * -EINVAL    : The value of @n is negative.
  */
-int eventfd_signal(struct file *file, int n)
+int eventfd_signal(struct eventfd_ctx *ctx, int n)
 {
-       struct eventfd_ctx *ctx = file->private_data;
        unsigned long flags;
 
        if (n < 0)
@@ -59,9 +68,45 @@ int eventfd_signal(struct file *file, int n)
 }
 EXPORT_SYMBOL_GPL(eventfd_signal);
 
+static void eventfd_free(struct kref *kref)
+{
+       struct eventfd_ctx *ctx = container_of(kref, struct eventfd_ctx, kref);
+
+       kfree(ctx);
+}
+
+/**
+ * eventfd_ctx_get - Acquires a reference to the internal eventfd context.
+ * @ctx: [in] Pointer to the eventfd context.
+ *
+ * Returns: In case of success, returns a pointer to the eventfd context.
+ */
+struct eventfd_ctx *eventfd_ctx_get(struct eventfd_ctx *ctx)
+{
+       kref_get(&ctx->kref);
+       return ctx;
+}
+EXPORT_SYMBOL_GPL(eventfd_ctx_get);
+
+/**
+ * eventfd_ctx_put - Releases a reference to the internal eventfd context.
+ * @ctx: [in] Pointer to eventfd context.
+ *
+ * The eventfd context reference must have been previously acquired either
+ * with eventfd_ctx_get() or eventfd_ctx_fdget()).
+ */
+void eventfd_ctx_put(struct eventfd_ctx *ctx)
+{
+       kref_put(&ctx->kref, eventfd_free);
+}
+EXPORT_SYMBOL_GPL(eventfd_ctx_put);
+
 static int eventfd_release(struct inode *inode, struct file *file)
 {
-       kfree(file->private_data);
+       struct eventfd_ctx *ctx = file->private_data;
+
+       wake_up_poll(&ctx->wqh, POLLHUP);
+       eventfd_ctx_put(ctx);
        return 0;
 }
 
@@ -185,6 +230,16 @@ static const struct file_operations eventfd_fops = {
        .write          = eventfd_write,
 };
 
+/**
+ * eventfd_fget - Acquire a reference of an eventfd file descriptor.
+ * @fd: [in] Eventfd file descriptor.
+ *
+ * Returns a pointer to the eventfd file structure in case of success, or the
+ * following error pointer:
+ *
+ * -EBADF    : Invalid @fd file descriptor.
+ * -EINVAL   : The @fd file descriptor is not an eventfd file.
+ */
 struct file *eventfd_fget(int fd)
 {
        struct file *file;
@@ -201,6 +256,48 @@ struct file *eventfd_fget(int fd)
 }
 EXPORT_SYMBOL_GPL(eventfd_fget);
 
+/**
+ * eventfd_ctx_fdget - Acquires a reference to the internal eventfd context.
+ * @fd: [in] Eventfd file descriptor.
+ *
+ * Returns a pointer to the internal eventfd context, otherwise the error
+ * pointers returned by the following functions:
+ *
+ * eventfd_fget
+ */
+struct eventfd_ctx *eventfd_ctx_fdget(int fd)
+{
+       struct file *file;
+       struct eventfd_ctx *ctx;
+
+       file = eventfd_fget(fd);
+       if (IS_ERR(file))
+               return (struct eventfd_ctx *) file;
+       ctx = eventfd_ctx_get(file->private_data);
+       fput(file);
+
+       return ctx;
+}
+EXPORT_SYMBOL_GPL(eventfd_ctx_fdget);
+
+/**
+ * eventfd_ctx_fileget - Acquires a reference to the internal eventfd context.
+ * @file: [in] Eventfd file pointer.
+ *
+ * Returns a pointer to the internal eventfd context, otherwise the error
+ * pointer:
+ *
+ * -EINVAL   : The @fd file descriptor is not an eventfd file.
+ */
+struct eventfd_ctx *eventfd_ctx_fileget(struct file *file)
+{
+       if (file->f_op != &eventfd_fops)
+               return ERR_PTR(-EINVAL);
+
+       return eventfd_ctx_get(file->private_data);
+}
+EXPORT_SYMBOL_GPL(eventfd_ctx_fileget);
+
 SYSCALL_DEFINE2(eventfd2, unsigned int, count, int, flags)
 {
        int fd;
@@ -217,6 +314,7 @@ SYSCALL_DEFINE2(eventfd2, unsigned int, count, int, flags)
        if (!ctx)
                return -ENOMEM;
 
+       kref_init(&ctx->kref);
        init_waitqueue_head(&ctx->wqh);
        ctx->count = count;
        ctx->flags = flags;
index 6524eca..e1dedb0 100644 (file)
@@ -66,8 +66,16 @@ static struct dentry *ext2_lookup(struct inode * dir, struct dentry *dentry, str
        inode = NULL;
        if (ino) {
                inode = ext2_iget(dir->i_sb, ino);
-               if (IS_ERR(inode))
-                       return ERR_CAST(inode);
+               if (unlikely(IS_ERR(inode))) {
+                       if (PTR_ERR(inode) == -ESTALE) {
+                               ext2_error(dir->i_sb, __func__,
+                                               "deleted inode referenced: %lu",
+                                               ino);
+                               return ERR_PTR(-EIO);
+                       } else {
+                               return ERR_CAST(inode);
+                       }
+               }
        }
        return d_splice_alias(inode, dentry);
 }
index 8fed2ed..f58ecbc 100644 (file)
@@ -849,6 +849,81 @@ err:
        return err;
 }
 
+static int fuse_notify_inval_inode(struct fuse_conn *fc, unsigned int size,
+                                  struct fuse_copy_state *cs)
+{
+       struct fuse_notify_inval_inode_out outarg;
+       int err = -EINVAL;
+
+       if (size != sizeof(outarg))
+               goto err;
+
+       err = fuse_copy_one(cs, &outarg, sizeof(outarg));
+       if (err)
+               goto err;
+       fuse_copy_finish(cs);
+
+       down_read(&fc->killsb);
+       err = -ENOENT;
+       if (!fc->sb)
+               goto err_unlock;
+
+       err = fuse_reverse_inval_inode(fc->sb, outarg.ino,
+                                      outarg.off, outarg.len);
+
+err_unlock:
+       up_read(&fc->killsb);
+       return err;
+
+err:
+       fuse_copy_finish(cs);
+       return err;
+}
+
+static int fuse_notify_inval_entry(struct fuse_conn *fc, unsigned int size,
+                                  struct fuse_copy_state *cs)
+{
+       struct fuse_notify_inval_entry_out outarg;
+       int err = -EINVAL;
+       char buf[FUSE_NAME_MAX+1];
+       struct qstr name;
+
+       if (size < sizeof(outarg))
+               goto err;
+
+       err = fuse_copy_one(cs, &outarg, sizeof(outarg));
+       if (err)
+               goto err;
+
+       err = -ENAMETOOLONG;
+       if (outarg.namelen > FUSE_NAME_MAX)
+               goto err;
+
+       name.name = buf;
+       name.len = outarg.namelen;
+       err = fuse_copy_one(cs, buf, outarg.namelen + 1);
+       if (err)
+               goto err;
+       fuse_copy_finish(cs);
+       buf[outarg.namelen] = 0;
+       name.hash = full_name_hash(name.name, name.len);
+
+       down_read(&fc->killsb);
+       err = -ENOENT;
+       if (!fc->sb)
+               goto err_unlock;
+
+       err = fuse_reverse_inval_entry(fc->sb, outarg.parent, &name);
+
+err_unlock:
+       up_read(&fc->killsb);
+       return err;
+
+err:
+       fuse_copy_finish(cs);
+       return err;
+}
+
 static int fuse_notify(struct fuse_conn *fc, enum fuse_notify_code code,
                       unsigned int size, struct fuse_copy_state *cs)
 {
@@ -856,6 +931,12 @@ static int fuse_notify(struct fuse_conn *fc, enum fuse_notify_code code,
        case FUSE_NOTIFY_POLL:
                return fuse_notify_poll(fc, size, cs);
 
+       case FUSE_NOTIFY_INVAL_INODE:
+               return fuse_notify_inval_inode(fc, size, cs);
+
+       case FUSE_NOTIFY_INVAL_ENTRY:
+               return fuse_notify_inval_entry(fc, size, cs);
+
        default:
                fuse_copy_finish(cs);
                return -EINVAL;
@@ -910,7 +991,7 @@ static ssize_t fuse_dev_write(struct kiocb *iocb, const struct iovec *iov,
                               unsigned long nr_segs, loff_t pos)
 {
        int err;
-       unsigned nbytes = iov_length(iov, nr_segs);
+       size_t nbytes = iov_length(iov, nr_segs);
        struct fuse_req *req;
        struct fuse_out_header oh;
        struct fuse_copy_state cs;
index b3089a0..e703654 100644 (file)
@@ -375,7 +375,7 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode,
        struct fuse_conn *fc = get_fuse_conn(dir);
        struct fuse_req *req;
        struct fuse_req *forget_req;
-       struct fuse_open_in inarg;
+       struct fuse_create_in inarg;
        struct fuse_open_out outopen;
        struct fuse_entry_out outentry;
        struct fuse_file *ff;
@@ -399,15 +399,20 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode,
        if (!ff)
                goto out_put_request;
 
+       if (!fc->dont_mask)
+               mode &= ~current_umask();
+
        flags &= ~O_NOCTTY;
        memset(&inarg, 0, sizeof(inarg));
        memset(&outentry, 0, sizeof(outentry));
        inarg.flags = flags;
        inarg.mode = mode;
+       inarg.umask = current_umask();
        req->in.h.opcode = FUSE_CREATE;
        req->in.h.nodeid = get_node_id(dir);
        req->in.numargs = 2;
-       req->in.args[0].size = sizeof(inarg);
+       req->in.args[0].size = fc->minor < 12 ? sizeof(struct fuse_open_in) :
+                                               sizeof(inarg);
        req->in.args[0].value = &inarg;
        req->in.args[1].size = entry->d_name.len + 1;
        req->in.args[1].value = entry->d_name.name;
@@ -546,12 +551,17 @@ static int fuse_mknod(struct inode *dir, struct dentry *entry, int mode,
        if (IS_ERR(req))
                return PTR_ERR(req);
 
+       if (!fc->dont_mask)
+               mode &= ~current_umask();
+
        memset(&inarg, 0, sizeof(inarg));
        inarg.mode = mode;
        inarg.rdev = new_encode_dev(rdev);
+       inarg.umask = current_umask();
        req->in.h.opcode = FUSE_MKNOD;
        req->in.numargs = 2;
-       req->in.args[0].size = sizeof(inarg);
+       req->in.args[0].size = fc->minor < 12 ? FUSE_COMPAT_MKNOD_IN_SIZE :
+                                               sizeof(inarg);
        req->in.args[0].value = &inarg;
        req->in.args[1].size = entry->d_name.len + 1;
        req->in.args[1].value = entry->d_name.name;
@@ -578,8 +588,12 @@ static int fuse_mkdir(struct inode *dir, struct dentry *entry, int mode)
        if (IS_ERR(req))
                return PTR_ERR(req);
 
+       if (!fc->dont_mask)
+               mode &= ~current_umask();
+
        memset(&inarg, 0, sizeof(inarg));
        inarg.mode = mode;
+       inarg.umask = current_umask();
        req->in.h.opcode = FUSE_MKDIR;
        req->in.numargs = 2;
        req->in.args[0].size = sizeof(inarg);
@@ -845,6 +859,43 @@ int fuse_update_attributes(struct inode *inode, struct kstat *stat,
        return err;
 }
 
+int fuse_reverse_inval_entry(struct super_block *sb, u64 parent_nodeid,
+                            struct qstr *name)
+{
+       int err = -ENOTDIR;
+       struct inode *parent;
+       struct dentry *dir;
+       struct dentry *entry;
+
+       parent = ilookup5(sb, parent_nodeid, fuse_inode_eq, &parent_nodeid);
+       if (!parent)
+               return -ENOENT;
+
+       mutex_lock(&parent->i_mutex);
+       if (!S_ISDIR(parent->i_mode))
+               goto unlock;
+
+       err = -ENOENT;
+       dir = d_find_alias(parent);
+       if (!dir)
+               goto unlock;
+
+       entry = d_lookup(dir, name);
+       dput(dir);
+       if (!entry)
+               goto unlock;
+
+       fuse_invalidate_attr(parent);
+       fuse_invalidate_entry(entry);
+       dput(entry);
+       err = 0;
+
+ unlock:
+       mutex_unlock(&parent->i_mutex);
+       iput(parent);
+       return err;
+}
+
 /*
  * Calling into a user-controlled filesystem gives the filesystem
  * daemon ptrace-like capabilities over the requester process.  This
index fce6ce6..cbc4640 100644 (file)
@@ -1922,7 +1922,7 @@ unsigned fuse_file_poll(struct file *file, poll_table *wait)
 
        req = fuse_get_req(fc);
        if (IS_ERR(req))
-               return PTR_ERR(req);
+               return POLLERR;
 
        req->in.h.opcode = FUSE_POLL;
        req->in.h.nodeid = ff->nodeid;
index aaf2f9f..52b641f 100644 (file)
@@ -446,6 +446,9 @@ struct fuse_conn {
        /** Do multi-page cached writes */
        unsigned big_writes:1;
 
+       /** Don't apply umask to creation modes */
+       unsigned dont_mask:1;
+
        /** The number of requests waiting for completion */
        atomic_t num_waiting;
 
@@ -481,6 +484,12 @@ struct fuse_conn {
 
        /** Called on final put */
        void (*release)(struct fuse_conn *);
+
+       /** Super block for this connection. */
+       struct super_block *sb;
+
+       /** Read/write semaphore to hold when accessing sb. */
+       struct rw_semaphore killsb;
 };
 
 static inline struct fuse_conn *get_fuse_conn_super(struct super_block *sb)
@@ -509,6 +518,11 @@ extern const struct file_operations fuse_dev_operations;
 extern const struct dentry_operations fuse_dentry_operations;
 
 /**
+ * Inode to nodeid comparison.
+ */
+int fuse_inode_eq(struct inode *inode, void *_nodeidp);
+
+/**
  * Get a filled in inode
  */
 struct inode *fuse_iget(struct super_block *sb, u64 nodeid,
@@ -708,6 +722,19 @@ void fuse_release_nowrite(struct inode *inode);
 
 u64 fuse_get_attr_version(struct fuse_conn *fc);
 
+/**
+ * File-system tells the kernel to invalidate cache for the given node id.
+ */
+int fuse_reverse_inval_inode(struct super_block *sb, u64 nodeid,
+                            loff_t offset, loff_t len);
+
+/**
+ * File-system tells the kernel to invalidate parent attributes and
+ * the dentry matching parent/name.
+ */
+int fuse_reverse_inval_entry(struct super_block *sb, u64 parent_nodeid,
+                            struct qstr *name);
+
 int fuse_do_open(struct fuse_conn *fc, u64 nodeid, struct file *file,
                 bool isdir);
 ssize_t fuse_direct_io(struct file *file, const char __user *buf,
index d8673cc..f91ccc4 100644 (file)
@@ -206,7 +206,7 @@ static void fuse_init_inode(struct inode *inode, struct fuse_attr *attr)
                BUG();
 }
 
-static int fuse_inode_eq(struct inode *inode, void *_nodeidp)
+int fuse_inode_eq(struct inode *inode, void *_nodeidp)
 {
        u64 nodeid = *(u64 *) _nodeidp;
        if (get_node_id(inode) == nodeid)
@@ -257,6 +257,31 @@ struct inode *fuse_iget(struct super_block *sb, u64 nodeid,
        return inode;
 }
 
+int fuse_reverse_inval_inode(struct super_block *sb, u64 nodeid,
+                            loff_t offset, loff_t len)
+{
+       struct inode *inode;
+       pgoff_t pg_start;
+       pgoff_t pg_end;
+
+       inode = ilookup5(sb, nodeid, fuse_inode_eq, &nodeid);
+       if (!inode)
+               return -ENOENT;
+
+       fuse_invalidate_attr(inode);
+       if (offset >= 0) {
+               pg_start = offset >> PAGE_CACHE_SHIFT;
+               if (len <= 0)
+                       pg_end = -1;
+               else
+                       pg_end = (offset + len - 1) >> PAGE_CACHE_SHIFT;
+               invalidate_inode_pages2_range(inode->i_mapping,
+                                             pg_start, pg_end);
+       }
+       iput(inode);
+       return 0;
+}
+
 static void fuse_umount_begin(struct super_block *sb)
 {
        fuse_abort_conn(get_fuse_conn_super(sb));
@@ -480,6 +505,7 @@ void fuse_conn_init(struct fuse_conn *fc)
        memset(fc, 0, sizeof(*fc));
        spin_lock_init(&fc->lock);
        mutex_init(&fc->inst_mutex);
+       init_rwsem(&fc->killsb);
        atomic_set(&fc->count, 1);
        init_waitqueue_head(&fc->waitq);
        init_waitqueue_head(&fc->blocked_waitq);
@@ -725,6 +751,8 @@ static void process_init_reply(struct fuse_conn *fc, struct fuse_req *req)
                        }
                        if (arg->flags & FUSE_BIG_WRITES)
                                fc->big_writes = 1;
+                       if (arg->flags & FUSE_DONT_MASK)
+                               fc->dont_mask = 1;
                } else {
                        ra_pages = fc->max_read / PAGE_CACHE_SIZE;
                        fc->no_lock = 1;
@@ -748,7 +776,7 @@ static void fuse_send_init(struct fuse_conn *fc, struct fuse_req *req)
        arg->minor = FUSE_KERNEL_MINOR_VERSION;
        arg->max_readahead = fc->bdi.ra_pages * PAGE_CACHE_SIZE;
        arg->flags |= FUSE_ASYNC_READ | FUSE_POSIX_LOCKS | FUSE_ATOMIC_O_TRUNC |
-               FUSE_EXPORT_SUPPORT | FUSE_BIG_WRITES;
+               FUSE_EXPORT_SUPPORT | FUSE_BIG_WRITES | FUSE_DONT_MASK;
        req->in.h.opcode = FUSE_INIT;
        req->in.numargs = 1;
        req->in.args[0].size = sizeof(*arg);
@@ -860,10 +888,16 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent)
        fuse_conn_init(fc);
 
        fc->dev = sb->s_dev;
+       fc->sb = sb;
        err = fuse_bdi_init(fc, sb);
        if (err)
                goto err_put_conn;
 
+       /* Handle umasking inside the fuse code */
+       if (sb->s_flags & MS_POSIXACL)
+               fc->dont_mask = 1;
+       sb->s_flags |= MS_POSIXACL;
+
        fc->release = fuse_free_conn;
        fc->flags = d.flags;
        fc->user_id = d.user_id;
@@ -941,12 +975,25 @@ static int fuse_get_sb(struct file_system_type *fs_type,
        return get_sb_nodev(fs_type, flags, raw_data, fuse_fill_super, mnt);
 }
 
+static void fuse_kill_sb_anon(struct super_block *sb)
+{
+       struct fuse_conn *fc = get_fuse_conn_super(sb);
+
+       if (fc) {
+               down_write(&fc->killsb);
+               fc->sb = NULL;
+               up_write(&fc->killsb);
+       }
+
+       kill_anon_super(sb);
+}
+
 static struct file_system_type fuse_fs_type = {
        .owner          = THIS_MODULE,
        .name           = "fuse",
        .fs_flags       = FS_HAS_SUBTYPE,
        .get_sb         = fuse_get_sb,
-       .kill_sb        = kill_anon_super,
+       .kill_sb        = fuse_kill_sb_anon,
 };
 
 #ifdef CONFIG_BLOCK
@@ -958,11 +1005,24 @@ static int fuse_get_sb_blk(struct file_system_type *fs_type,
                           mnt);
 }
 
+static void fuse_kill_sb_blk(struct super_block *sb)
+{
+       struct fuse_conn *fc = get_fuse_conn_super(sb);
+
+       if (fc) {
+               down_write(&fc->killsb);
+               fc->sb = NULL;
+               up_write(&fc->killsb);
+       }
+
+       kill_block_super(sb);
+}
+
 static struct file_system_type fuseblk_fs_type = {
        .owner          = THIS_MODULE,
        .name           = "fuseblk",
        .get_sb         = fuse_get_sb_blk,
-       .kill_sb        = kill_block_super,
+       .kill_sb        = fuse_kill_sb_blk,
        .fs_flags       = FS_REQUIRES_DEV | FS_HAS_SUBTYPE,
 };
 
index fe02ad4..032604e 100644 (file)
@@ -972,6 +972,7 @@ static int hostfs_fill_sb_common(struct super_block *sb, void *d, int silent)
        sb->s_blocksize_bits = 10;
        sb->s_magic = HOSTFS_SUPER_MAGIC;
        sb->s_op = &hostfs_sbops;
+       sb->s_maxbytes = MAX_LFS_FILESIZE;
 
        /* NULL is printed as <NULL> by sprintf: avoid that. */
        if (req_root == NULL)
index 7515e73..696686c 100644 (file)
@@ -130,9 +130,9 @@ int jffs2_scan_medium(struct jffs2_sb_info *c)
        if (jffs2_sum_active()) {
                s = kzalloc(sizeof(struct jffs2_summary), GFP_KERNEL);
                if (!s) {
-                       kfree(flashbuf);
                        JFFS2_WARNING("Can't allocate memory for summary\n");
-                       return -ENOMEM;
+                       ret = -ENOMEM;
+                       goto out;
                }
        }
 
index 5b961eb..f3c5b27 100644 (file)
@@ -1761,6 +1761,10 @@ do_last:
                        goto exit;
                }
                filp = nameidata_to_filp(&nd, open_flag);
+               if (IS_ERR(filp))
+                       ima_counts_put(&nd.path,
+                                      acc_mode & (MAY_READ | MAY_WRITE |
+                                                  MAY_EXEC));
                mnt_drop_write(nd.path.mnt);
                if (nd.root.mnt)
                        path_put(&nd.root);
@@ -1817,6 +1821,9 @@ ok:
                goto exit;
        }
        filp = nameidata_to_filp(&nd, open_flag);
+       if (IS_ERR(filp))
+               ima_counts_put(&nd.path,
+                              acc_mode & (MAY_READ | MAY_WRITE | MAY_EXEC));
        /*
         * It is now safe to drop the mnt write
         * because the filp has had a write taken
index 4145083..23341c1 100644 (file)
@@ -678,7 +678,6 @@ __be32
 nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
                        int access, struct file **filp)
 {
-       const struct cred *cred = current_cred();
        struct dentry   *dentry;
        struct inode    *inode;
        int             flags = O_RDONLY|O_LARGEFILE;
@@ -733,7 +732,7 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
                vfs_dq_init(inode);
        }
        *filp = dentry_open(dget(dentry), mntget(fhp->fh_export->ex_path.mnt),
-                           flags, cred);
+                           flags, current_cred());
        if (IS_ERR(*filp))
                host_err = PTR_ERR(*filp);
        else
index ff231ad..ff27a29 100644 (file)
@@ -296,12 +296,15 @@ static int inotify_fasync(int fd, struct file *file, int on)
 static int inotify_release(struct inode *ignored, struct file *file)
 {
        struct fsnotify_group *group = file->private_data;
+       struct user_struct *user = group->inotify_data.user;
 
        fsnotify_clear_marks_by_group(group);
 
        /* free this group, matching get was inotify_init->fsnotify_obtain_group */
        fsnotify_put_group(group);
 
+       atomic_dec(&user->inotify_devs);
+
        return 0;
 }
 
index d7d50d7..aa00800 100644 (file)
@@ -97,4 +97,8 @@ extern void setup_per_cpu_areas(void);
 #define PER_CPU_ATTRIBUTES
 #endif
 
+#ifndef PER_CPU_DEF_ATTRIBUTES
+#define PER_CPU_DEF_ATTRIBUTES
+#endif
+
 #endif /* _ASM_GENERIC_PERCPU_H_ */
index 92b73b6..a553f10 100644 (file)
        . = ALIGN(align);                                               \
        *(.data.cacheline_aligned)
 
-#define INIT_TASK(align)                                               \
+#define INIT_TASK_DATA(align)                                          \
        . = ALIGN(align);                                               \
        *(.data.init_task)
 
 /*
  * Init task
  */
-#define INIT_TASK_DATA(align)                                          \
+#define INIT_TASK_DATA_SECTION(align)                                  \
        . = ALIGN(align);                                               \
        .data.init_task : {                                             \
-               INIT_TASK                                               \
+               INIT_TASK_DATA(align)                                   \
        }
 
 #ifdef CONFIG_CONSTRUCTORS
-#define KERNEL_CTORS() VMLINUX_SYMBOL(__ctors_start) = .; \
+#define KERNEL_CTORS() . = ALIGN(8);                      \
+                       VMLINUX_SYMBOL(__ctors_start) = .; \
                        *(.ctors)                          \
                        VMLINUX_SYMBOL(__ctors_end) = .;
 #else
  * matches the requirment of PAGE_ALIGNED_DATA.
  *
  * use 0 as page_align if page_aligned data is not used */
-#define RW_DATA_SECTION(cacheline, nosave, pagealigned, inittask)      \
+#define RW_DATA_SECTION(cacheline, pagealigned, inittask)              \
        . = ALIGN(PAGE_SIZE);                                           \
        .data : AT(ADDR(.data) - LOAD_OFFSET) {                         \
-               INIT_TASK(inittask)                                     \
+               INIT_TASK_DATA(inittask)                                \
                CACHELINE_ALIGNED_DATA(cacheline)                       \
                READ_MOSTLY_DATA(cacheline)                             \
                DATA_DATA                                               \
                CONSTRUCTORS                                            \
-               NOSAVE_DATA(nosave)                                     \
+               NOSAVE_DATA                                             \
                PAGE_ALIGNED_DATA(pagealigned)                          \
        }
 
index c263e4d..7d6c9a2 100644 (file)
@@ -35,11 +35,11 @@ struct est_timings {
 } __attribute__((packed));
 
 /* 00=16:10, 01=4:3, 10=5:4, 11=16:9 */
-#define EDID_TIMING_ASPECT_SHIFT 0
+#define EDID_TIMING_ASPECT_SHIFT 6
 #define EDID_TIMING_ASPECT_MASK  (0x3 << EDID_TIMING_ASPECT_SHIFT)
 
 /* need to add 60 */
-#define EDID_TIMING_VFREQ_SHIFT  2
+#define EDID_TIMING_VFREQ_SHIFT  0
 #define EDID_TIMING_VFREQ_MASK   (0x3f << EDID_TIMING_VFREQ_SHIFT)
 
 struct std_timing {
@@ -47,11 +47,11 @@ struct std_timing {
        u8 vfreq_aspect;
 } __attribute__((packed));
 
-#define DRM_EDID_PT_HSYNC_POSITIVE (1 << 6)
-#define DRM_EDID_PT_VSYNC_POSITIVE (1 << 5)
+#define DRM_EDID_PT_HSYNC_POSITIVE (1 << 1)
+#define DRM_EDID_PT_VSYNC_POSITIVE (1 << 2)
 #define DRM_EDID_PT_SEPARATE_SYNC  (3 << 3)
-#define DRM_EDID_PT_STEREO         (1 << 2)
-#define DRM_EDID_PT_INTERLACED     (1 << 1)
+#define DRM_EDID_PT_STEREO         (1 << 5)
+#define DRM_EDID_PT_INTERLACED     (1 << 7)
 
 /* If detailed data is pixel timing */
 struct detailed_pixel_timing {
@@ -93,7 +93,7 @@ struct detailed_data_monitor_range {
 } __attribute__((packed));
 
 struct detailed_data_wpindex {
-       u8 white_xy_lo; /* Upper 2 bits each */
+       u8 white_yx_lo; /* Lower 2 bits each */
        u8 white_x_hi;
        u8 white_y_hi;
        u8 gamma; /* need to divide by 100 then add 1 */
@@ -135,21 +135,21 @@ struct detailed_timing {
        } data;
 } __attribute__((packed));
 
-#define DRM_EDID_INPUT_SERRATION_VSYNC (1 << 7)
-#define DRM_EDID_INPUT_SYNC_ON_GREEN   (1 << 5)
-#define DRM_EDID_INPUT_COMPOSITE_SYNC  (1 << 4)
+#define DRM_EDID_INPUT_SERRATION_VSYNC (1 << 0)
+#define DRM_EDID_INPUT_SYNC_ON_GREEN   (1 << 1)
+#define DRM_EDID_INPUT_COMPOSITE_SYNC  (1 << 2)
 #define DRM_EDID_INPUT_SEPARATE_SYNCS  (1 << 3)
-#define DRM_EDID_INPUT_BLANK_TO_BLACK  (1 << 2)
-#define DRM_EDID_INPUT_VIDEO_LEVEL     (3 << 1)
-#define DRM_EDID_INPUT_DIGITAL         (1 << 0) /* bits above must be zero if set */
+#define DRM_EDID_INPUT_BLANK_TO_BLACK  (1 << 4)
+#define DRM_EDID_INPUT_VIDEO_LEVEL     (3 << 5)
+#define DRM_EDID_INPUT_DIGITAL         (1 << 7) /* bits below must be zero if set */
 
-#define DRM_EDID_FEATURE_DEFAULT_GTF      (1 << 7)
-#define DRM_EDID_FEATURE_PREFERRED_TIMING (1 << 6)
-#define DRM_EDID_FEATURE_STANDARD_COLOR   (1 << 5)
+#define DRM_EDID_FEATURE_DEFAULT_GTF      (1 << 0)
+#define DRM_EDID_FEATURE_PREFERRED_TIMING (1 << 1)
+#define DRM_EDID_FEATURE_STANDARD_COLOR   (1 << 2)
 #define DRM_EDID_FEATURE_DISPLAY_TYPE     (3 << 3) /* 00=mono, 01=rgb, 10=non-rgb, 11=unknown */
-#define DRM_EDID_FEATURE_PM_ACTIVE_OFF    (1 << 2)
-#define DRM_EDID_FEATURE_PM_SUSPEND       (1 << 1)
-#define DRM_EDID_FEATURE_PM_STANDBY       (1 << 0)
+#define DRM_EDID_FEATURE_PM_ACTIVE_OFF    (1 << 5)
+#define DRM_EDID_FEATURE_PM_SUSPEND       (1 << 6)
+#define DRM_EDID_FEATURE_PM_STANDBY       (1 << 7)
 
 struct edid {
        u8 header[8];
index b16a957..47f7d93 100644 (file)
@@ -121,9 +121,9 @@ struct kiocb {
 
        /*
         * If the aio_resfd field of the userspace iocb is not zero,
-        * this is the underlying file* to deliver event to.
+        * this is the underlying eventfd context to deliver events to.
         */
-       struct file             *ki_eventfd;
+       struct eventfd_ctx      *ki_eventfd;
 };
 
 #define is_sync_kiocb(iocb)    ((iocb)->ki_key == KIOCB_SYNC_KEY)
index 2a04eb5..2892b71 100644 (file)
@@ -319,7 +319,6 @@ static inline int bio_has_allocated_vec(struct bio *bio)
  */
 struct bio_integrity_payload {
        struct bio              *bip_bio;       /* parent bio */
-       struct bio_vec          *bip_vec;       /* integrity data vector */
 
        sector_t                bip_sector;     /* virtual start sector */
 
@@ -328,11 +327,12 @@ struct bio_integrity_payload {
 
        unsigned int            bip_size;
 
-       unsigned short          bip_pool;       /* pool the ivec came from */
+       unsigned short          bip_slab;       /* slab the bip came from */
        unsigned short          bip_vcnt;       /* # of integrity bio_vecs */
        unsigned short          bip_idx;        /* current bip_vec index */
 
        struct work_struct      bip_work;       /* I/O completion */
+       struct bio_vec          bip_vec[0];     /* embedded bvec array */
 };
 #endif /* CONFIG_BLK_DEV_INTEGRITY */
 
@@ -430,6 +430,9 @@ struct bio_set {
        unsigned int front_pad;
 
        mempool_t *bio_pool;
+#if defined(CONFIG_BLK_DEV_INTEGRITY)
+       mempool_t *bio_integrity_pool;
+#endif
        mempool_t *bvec_pool;
 };
 
@@ -634,8 +637,9 @@ static inline struct bio *bio_list_get(struct bio_list *bl)
 
 #define bio_integrity(bio) (bio->bi_integrity != NULL)
 
+extern struct bio_integrity_payload *bio_integrity_alloc_bioset(struct bio *, gfp_t, unsigned int, struct bio_set *);
 extern struct bio_integrity_payload *bio_integrity_alloc(struct bio *, gfp_t, unsigned int);
-extern void bio_integrity_free(struct bio *);
+extern void bio_integrity_free(struct bio *, struct bio_set *);
 extern int bio_integrity_add_page(struct bio *, struct page *, unsigned int, unsigned int);
 extern int bio_integrity_enabled(struct bio *bio);
 extern int bio_integrity_set_tag(struct bio *, void *, unsigned int);
@@ -645,21 +649,27 @@ extern void bio_integrity_endio(struct bio *, int);
 extern void bio_integrity_advance(struct bio *, unsigned int);
 extern void bio_integrity_trim(struct bio *, unsigned int, unsigned int);
 extern void bio_integrity_split(struct bio *, struct bio_pair *, int);
-extern int bio_integrity_clone(struct bio *, struct bio *, gfp_t);
+extern int bio_integrity_clone(struct bio *, struct bio *, gfp_t, struct bio_set *);
+extern int bioset_integrity_create(struct bio_set *, int);
+extern void bioset_integrity_free(struct bio_set *);
+extern void bio_integrity_init(void);
 
 #else /* CONFIG_BLK_DEV_INTEGRITY */
 
 #define bio_integrity(a)               (0)
+#define bioset_integrity_create(a, b)  (0)
 #define bio_integrity_prep(a)          (0)
 #define bio_integrity_enabled(a)       (0)
-#define bio_integrity_clone(a, b, c)   (0)
-#define bio_integrity_free(a)          do { } while (0)
+#define bio_integrity_clone(a, b, c, d)        (0)
+#define bioset_integrity_free(a)       do { } while (0)
+#define bio_integrity_free(a, b)       do { } while (0)
 #define bio_integrity_endio(a, b)      do { } while (0)
 #define bio_integrity_advance(a, b)    do { } while (0)
 #define bio_integrity_trim(a, b, c)    do { } while (0)
 #define bio_integrity_split(a, b, c)   do { } while (0)
 #define bio_integrity_set_tag(a, b, c) do { } while (0)
 #define bio_integrity_get_tag(a, b, c) do { } while (0)
+#define bio_integrity_init(a)          do { } while (0)
 
 #endif /* CONFIG_BLK_DEV_INTEGRITY */
 
index 8963d91..49ae079 100644 (file)
@@ -301,12 +301,6 @@ struct blk_queue_tag {
 #define BLK_SCSI_MAX_CMDS      (256)
 #define BLK_SCSI_CMD_PER_LONG  (BLK_SCSI_MAX_CMDS / (sizeof(long) * 8))
 
-struct blk_cmd_filter {
-       unsigned long read_ok[BLK_SCSI_CMD_PER_LONG];
-       unsigned long write_ok[BLK_SCSI_CMD_PER_LONG];
-       struct kobject kobj;
-};
-
 struct queue_limits {
        unsigned long           bounce_pfn;
        unsigned long           seg_boundary_mask;
@@ -445,7 +439,6 @@ struct request_queue
 #if defined(CONFIG_BLK_DEV_BSG)
        struct bsg_class_device bsg_dev;
 #endif
-       struct blk_cmd_filter cmd_filter;
 };
 
 #define QUEUE_FLAG_CLUSTER     0       /* cluster several segments into 1 */
@@ -998,13 +991,7 @@ static inline int sb_issue_discard(struct super_block *sb,
        return blkdev_issue_discard(sb->s_bdev, block, nr_blocks, GFP_KERNEL);
 }
 
-/*
-* command filter functions
-*/
-extern int blk_verify_command(struct blk_cmd_filter *filter,
-                             unsigned char *cmd, fmode_t has_write_perm);
-extern void blk_unregister_filter(struct gendisk *disk);
-extern void blk_set_cmd_filter_defaults(struct blk_cmd_filter *filter);
+extern int blk_verify_command(unsigned char *cmd, fmode_t has_write_perm);
 
 #define MAX_PHYS_SEGMENTS 128
 #define MAX_HW_SEGMENTS 128
index b68d278..47ebf41 100644 (file)
@@ -136,7 +136,7 @@ struct cn_callback_data {
        void *ddata;
        
        void *callback_priv;
-       void (*callback) (void *);
+       void (*callback) (struct cn_msg *);
 
        void *free;
 };
@@ -167,11 +167,11 @@ struct cn_dev {
        struct cn_queue_dev *cbdev;
 };
 
-int cn_add_callback(struct cb_id *, char *, void (*callback) (void *));
+int cn_add_callback(struct cb_id *, char *, void (*callback) (struct cn_msg *));
 void cn_del_callback(struct cb_id *);
 int cn_netlink_send(struct cn_msg *, u32, gfp_t);
 
-int cn_queue_add_callback(struct cn_queue_dev *dev, char *name, struct cb_id *id, void (*callback)(void *));
+int cn_queue_add_callback(struct cn_queue_dev *dev, char *name, struct cb_id *id, void (*callback)(struct cn_msg *));
 void cn_queue_del_callback(struct cn_queue_dev *dev, struct cb_id *id);
 
 int queue_cn_work(struct cn_callback_entry *cbq, struct work_struct *work);
index f45a8ae..3b85ba6 100644 (file)
@@ -8,10 +8,8 @@
 #ifndef _LINUX_EVENTFD_H
 #define _LINUX_EVENTFD_H
 
-#ifdef CONFIG_EVENTFD
-
-/* For O_CLOEXEC and O_NONBLOCK */
 #include <linux/fcntl.h>
+#include <linux/file.h>
 
 /*
  * CAREFUL: Check include/asm-generic/fcntl.h when defining
 #define EFD_SHARED_FCNTL_FLAGS (O_CLOEXEC | O_NONBLOCK)
 #define EFD_FLAGS_SET (EFD_SHARED_FCNTL_FLAGS | EFD_SEMAPHORE)
 
+#ifdef CONFIG_EVENTFD
+
+struct eventfd_ctx *eventfd_ctx_get(struct eventfd_ctx *ctx);
+void eventfd_ctx_put(struct eventfd_ctx *ctx);
 struct file *eventfd_fget(int fd);
-int eventfd_signal(struct file *file, int n);
+struct eventfd_ctx *eventfd_ctx_fdget(int fd);
+struct eventfd_ctx *eventfd_ctx_fileget(struct file *file);
+int eventfd_signal(struct eventfd_ctx *ctx, int n);
 
 #else /* CONFIG_EVENTFD */
 
-#define eventfd_fget(fd) ERR_PTR(-ENOSYS)
-static inline int eventfd_signal(struct file *file, int n)
-{ return 0; }
+/*
+ * Ugly ugly ugly error layer to support modules that uses eventfd but
+ * pretend to work in !CONFIG_EVENTFD configurations. Namely, AIO.
+ */
+static inline struct eventfd_ctx *eventfd_ctx_fdget(int fd)
+{
+       return ERR_PTR(-ENOSYS);
+}
+
+static inline int eventfd_signal(struct eventfd_ctx *ctx, int n)
+{
+       return -ENOSYS;
+}
+
+static inline void eventfd_ctx_put(struct eventfd_ctx *ctx)
+{
+
+}
 
-#endif /* CONFIG_EVENTFD */
+#endif
 
 #endif /* _LINUX_EVENTFD_H */
 
index dd68358..f847df9 100644 (file)
@@ -819,6 +819,7 @@ struct fb_info {
        int node;
        int flags;
        struct mutex lock;              /* Lock for open/release/ioctl funcs */
+       struct mutex mm_lock;           /* Lock for fb_mmap and smem_* fields */
        struct fb_var_screeninfo var;   /* Current var */
        struct fb_fix_screeninfo fix;   /* Current fix */
        struct fb_monspecs monspecs;    /* Current Monitor specs */
index 44848aa..6c3de99 100644 (file)
@@ -280,7 +280,7 @@ static inline void __fsnotify_update_dcache_flags(struct dentry *dentry)
        assert_spin_locked(&dentry->d_lock);
 
        parent = dentry->d_parent;
-       if (fsnotify_inode_watches_children(parent->d_inode))
+       if (parent->d_inode && fsnotify_inode_watches_children(parent->d_inode))
                dentry->d_flags |= DCACHE_FSNOTIFY_PARENT_WATCHED;
        else
                dentry->d_flags &= ~DCACHE_FSNOTIFY_PARENT_WATCHED;
index d41ed59..cf593bf 100644 (file)
  *  - add IOCTL message
  *  - add unsolicited notification support
  *  - add POLL message and NOTIFY_POLL notification
+ *
+ * 7.12
+ *  - add umask flag to input argument of open, mknod and mkdir
+ *  - add notification messages for invalidation of inodes and
+ *    directory entries
  */
 
 #ifndef _LINUX_FUSE_H
@@ -36,7 +41,7 @@
 #define FUSE_KERNEL_VERSION 7
 
 /** Minor version number of this interface */
-#define FUSE_KERNEL_MINOR_VERSION 11
+#define FUSE_KERNEL_MINOR_VERSION 12
 
 /** The node ID of the root inode */
 #define FUSE_ROOT_ID 1
@@ -112,6 +117,7 @@ struct fuse_file_lock {
  * INIT request/reply flags
  *
  * FUSE_EXPORT_SUPPORT: filesystem handles lookups of "." and ".."
+ * FUSE_DONT_MASK: don't apply umask to file mode on create operations
  */
 #define FUSE_ASYNC_READ                (1 << 0)
 #define FUSE_POSIX_LOCKS       (1 << 1)
@@ -119,6 +125,7 @@ struct fuse_file_lock {
 #define FUSE_ATOMIC_O_TRUNC    (1 << 3)
 #define FUSE_EXPORT_SUPPORT    (1 << 4)
 #define FUSE_BIG_WRITES                (1 << 5)
+#define FUSE_DONT_MASK         (1 << 6)
 
 /**
  * CUSE INIT request/reply flags
@@ -224,6 +231,8 @@ enum fuse_opcode {
 
 enum fuse_notify_code {
        FUSE_NOTIFY_POLL   = 1,
+       FUSE_NOTIFY_INVAL_INODE = 2,
+       FUSE_NOTIFY_INVAL_ENTRY = 3,
        FUSE_NOTIFY_CODE_MAX,
 };
 
@@ -262,14 +271,18 @@ struct fuse_attr_out {
        struct fuse_attr attr;
 };
 
+#define FUSE_COMPAT_MKNOD_IN_SIZE 8
+
 struct fuse_mknod_in {
        __u32   mode;
        __u32   rdev;
+       __u32   umask;
+       __u32   padding;
 };
 
 struct fuse_mkdir_in {
        __u32   mode;
-       __u32   padding;
+       __u32   umask;
 };
 
 struct fuse_rename_in {
@@ -301,7 +314,14 @@ struct fuse_setattr_in {
 
 struct fuse_open_in {
        __u32   flags;
+       __u32   unused;
+};
+
+struct fuse_create_in {
+       __u32   flags;
        __u32   mode;
+       __u32   umask;
+       __u32   padding;
 };
 
 struct fuse_open_out {
@@ -508,4 +528,16 @@ struct fuse_dirent {
 #define FUSE_DIRENT_SIZE(d) \
        FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET + (d)->namelen)
 
+struct fuse_notify_inval_inode_out {
+       __u64   ino;
+       __s64   off;
+       __s64   len;
+};
+
+struct fuse_notify_inval_entry_out {
+       __u64   parent;
+       __u32   namelen;
+       __u32   padding;
+};
+
 #endif /* _LINUX_FUSE_H */
index 7400900..54648e6 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/list.h>
 #include <linux/wait.h>
 #include <linux/percpu.h>
+#include <linux/timer.h>
 
 
 struct hrtimer_clock_base;
@@ -447,6 +448,8 @@ extern void timer_stats_update_stats(void *timer, pid_t pid, void *startf,
 
 static inline void timer_stats_account_hrtimer(struct hrtimer *timer)
 {
+       if (likely(!timer->start_pid))
+               return;
        timer_stats_update_stats(timer, timer->start_pid, timer->start_site,
                                 timer->function, timer->start_comm, 0);
 }
@@ -456,6 +459,8 @@ extern void __timer_stats_hrtimer_set_start_info(struct hrtimer *timer,
 
 static inline void timer_stats_hrtimer_set_start_info(struct hrtimer *timer)
 {
+       if (likely(!timer_stats_active))
+               return;
        __timer_stats_hrtimer_set_start_info(timer, __builtin_return_address(0));
 }
 
index 95c6e00..edc93a6 100644 (file)
@@ -1062,7 +1062,6 @@ int generic_ide_ioctl(ide_drive_t *, struct block_device *, unsigned, unsigned l
 extern int ide_vlb_clk;
 extern int ide_pci_clk;
 
-unsigned int ide_rq_bytes(struct request *);
 int ide_end_rq(ide_drive_t *, struct request *, int, unsigned int);
 void ide_kill_rq(ide_drive_t *, struct request *);
 
@@ -1361,7 +1360,6 @@ int ide_in_drive_list(u16 *, const struct drive_list_entry *);
 #ifdef CONFIG_BLK_DEV_IDEDMA
 int ide_dma_good_drive(ide_drive_t *);
 int __ide_dma_bad_drive(ide_drive_t *);
-int ide_id_dma_bug(ide_drive_t *);
 
 u8 ide_find_dma_mode(ide_drive_t *, u8);
 
@@ -1402,7 +1400,6 @@ void ide_dma_lost_irq(ide_drive_t *);
 ide_startstop_t ide_dma_timeout_retry(ide_drive_t *, int);
 
 #else
-static inline int ide_id_dma_bug(ide_drive_t *drive) { return 0; }
 static inline u8 ide_find_dma_mode(ide_drive_t *drive, u8 speed) { return 0; }
 static inline u8 ide_max_dma_mode(ide_drive_t *drive) { return 0; }
 static inline void ide_dma_off_quietly(ide_drive_t *drive) { ; }
@@ -1422,6 +1419,7 @@ static inline void ide_dma_unmap_sg(ide_drive_t *drive,
 
 #ifdef CONFIG_BLK_DEV_IDEACPI
 int ide_acpi_init(void);
+bool ide_port_acpi(ide_hwif_t *hwif);
 extern int ide_acpi_exec_tfs(ide_drive_t *drive);
 extern void ide_acpi_get_timing(ide_hwif_t *hwif);
 extern void ide_acpi_push_timing(ide_hwif_t *hwif);
@@ -1430,6 +1428,7 @@ void ide_acpi_port_init_devices(ide_hwif_t *);
 extern void ide_acpi_set_state(ide_hwif_t *hwif, int on);
 #else
 static inline int ide_acpi_init(void) { return 0; }
+static inline bool ide_port_acpi(ide_hwif_t *hwif) { return 0; }
 static inline int ide_acpi_exec_tfs(ide_drive_t *drive) { return 0; }
 static inline void ide_acpi_get_timing(ide_hwif_t *hwif) { ; }
 static inline void ide_acpi_push_timing(ide_hwif_t *hwif) { ; }
index a9173d5..23343ab 100644 (file)
@@ -1196,6 +1196,10 @@ enum ieee80211_sa_query_action {
 #define WLAN_CIPHER_SUITE_WEP104       0x000FAC05
 #define WLAN_CIPHER_SUITE_AES_CMAC     0x000FAC06
 
+/* AKM suite selectors */
+#define WLAN_AKM_SUITE_8021X           0x000FAC01
+#define WLAN_AKM_SUITE_PSK             0x000FAC02
+
 #define WLAN_MAX_KEY_LEN               32
 
 /**
index 915ba57..3f5fd52 100644 (file)
@@ -62,6 +62,7 @@
 #define TUN_F_TSO4     0x02    /* I can handle TSO for IPv4 packets */
 #define TUN_F_TSO6     0x04    /* I can handle TSO for IPv6 packets */
 #define TUN_F_TSO_ECN  0x08    /* I can handle TSO with ECN bits. */
+#define TUN_F_UFO      0x10    /* I can handle UFO packets */
 
 /* Protocol info prepended to the packets (when IFF_NO_PI is not set) */
 #define TUN_PKT_STRIP  0x0001
index b1b827d..0e3f2a4 100644 (file)
@@ -24,6 +24,7 @@ extern int ima_path_check(struct path *path, int mask, int update_counts);
 extern void ima_file_free(struct file *file);
 extern int ima_file_mmap(struct file *file, unsigned long prot);
 extern void ima_counts_get(struct file *file);
+extern void ima_counts_put(struct path *path, int mask);
 
 #else
 static inline int ima_bprm_check(struct linux_binprm *bprm)
@@ -60,5 +61,10 @@ static inline void ima_counts_get(struct file *file)
 {
        return;
 }
+
+static inline void ima_counts_put(struct path *path, int mask)
+{
+       return;
+}
 #endif /* CONFIG_IMA_H */
 #endif /* _LINUX_IMA_H */
index 5368fbd..7fc01b1 100644 (file)
@@ -183,5 +183,8 @@ extern struct cred init_cred;
        LIST_HEAD_INIT(cpu_timers[2]),                                  \
 }
 
+/* Attach to the init_task data structure for proper alignment */
+#define __init_task_data __attribute__((__section__(".data.init_task")))
+
 
 #endif
index fac104e..d6320a3 100644 (file)
@@ -303,6 +303,7 @@ extern int oops_in_progress;                /* If set, an oops, panic(), BUG() or die() is in
 extern int panic_timeout;
 extern int panic_on_oops;
 extern int panic_on_unrecovered_nmi;
+extern int panic_on_io_nmi;
 extern const char *print_tainted(void);
 extern void add_taint(unsigned flag);
 extern int test_taint(unsigned flag);
index aacc544..16713dc 100644 (file)
@@ -125,6 +125,7 @@ struct kvm_kernel_irq_routing_entry {
 struct kvm {
        struct mutex lock; /* protects the vcpus array and APIC accesses */
        spinlock_t mmu_lock;
+       spinlock_t requests_lock;
        struct rw_semaphore slots_lock;
        struct mm_struct *mm; /* userspace tied to this vm */
        int nmemslots;
diff --git a/include/linux/leds-lp3944.h b/include/linux/leds-lp3944.h
new file mode 100644 (file)
index 0000000..afc9f9f
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * leds-lp3944.h - platform data structure for lp3944 led controller
+ *
+ * Copyright (C) 2009 Antonio Ospite <ospite@studenti.unina.it>
+ *
+ * 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 __LINUX_LEDS_LP3944_H
+#define __LINUX_LEDS_LP3944_H
+
+#include <linux/leds.h>
+#include <linux/workqueue.h>
+
+#define LP3944_LED0 0
+#define LP3944_LED1 1
+#define LP3944_LED2 2
+#define LP3944_LED3 3
+#define LP3944_LED4 4
+#define LP3944_LED5 5
+#define LP3944_LED6 6
+#define LP3944_LED7 7
+#define LP3944_LEDS_MAX 8
+
+#define LP3944_LED_STATUS_MASK 0x03
+enum lp3944_status {
+       LP3944_LED_STATUS_OFF  = 0x0,
+       LP3944_LED_STATUS_ON   = 0x1,
+       LP3944_LED_STATUS_DIM0 = 0x2,
+       LP3944_LED_STATUS_DIM1 = 0x3
+};
+
+enum lp3944_type {
+       LP3944_LED_TYPE_NONE,
+       LP3944_LED_TYPE_LED,
+       LP3944_LED_TYPE_LED_INVERTED,
+};
+
+struct lp3944_led {
+       char *name;
+       enum lp3944_type type;
+       enum lp3944_status status;
+};
+
+struct lp3944_platform_data {
+       struct lp3944_led leds[LP3944_LEDS_MAX];
+       u8 leds_size;
+};
+
+#endif /* __LINUX_LEDS_LP3944_H */
index 376fe07..d8bf966 100644 (file)
@@ -45,7 +45,10 @@ struct led_classdev {
        /* Get LED brightness level */
        enum led_brightness (*brightness_get)(struct led_classdev *led_cdev);
 
-       /* Activate hardware accelerated blink */
+       /* Activate hardware accelerated blink, delays are in
+        * miliseconds and if none is provided then a sensible default
+        * should be chosen. The call can adjust the timings if it can't
+        * match the values specified exactly. */
        int             (*blink_set)(struct led_classdev *led_cdev,
                                     unsigned long *delay_on,
                                     unsigned long *delay_off);
@@ -141,9 +144,14 @@ struct gpio_led {
        const char *name;
        const char *default_trigger;
        unsigned        gpio;
-       u8              active_low : 1;
-       u8              retain_state_suspended : 1;
+       unsigned        active_low : 1;
+       unsigned        retain_state_suspended : 1;
+       unsigned        default_state : 2;
+       /* default_state should be one of LEDS_GPIO_DEFSTATE_(ON|OFF|KEEP) */
 };
+#define LEDS_GPIO_DEFSTATE_OFF 0
+#define LEDS_GPIO_DEFSTATE_ON  1
+#define LEDS_GPIO_DEFSTATE_KEEP        2
 
 struct gpio_led_platform_data {
        int             num_leds;
index fee9e59..691f591 100644 (file)
 #define __page_aligned_bss     __section(.bss.page_aligned) __aligned(PAGE_SIZE)
 
 /*
+ * For assembly routines.
+ *
+ * Note when using these that you must specify the appropriate
+ * alignment directives yourself
+ */
+#define __PAGE_ALIGNED_DATA    .section ".data.page_aligned", "aw"
+#define __PAGE_ALIGNED_BSS     .section ".bss.page_aligned", "aw"
+
+/*
  * This is used by architectures to keep arguments on the stack
  * untouched by the compiler by keeping them live until the end.
  * The argument stack may be owned by the assembly-language
index d006e93..ba3a7cb 100644 (file)
@@ -826,7 +826,7 @@ extern int make_pages_present(unsigned long addr, unsigned long end);
 extern int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, int len, int write);
 
 int get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
-                       unsigned long start, int len, int write, int force,
+                       unsigned long start, int nr_pages, int write, int force,
                        struct page **pages, struct vm_area_struct **vmas);
 int get_user_pages_fast(unsigned long start, int nr_pages, int write,
                        struct page **pages);
index 3ceb0cc..2a73946 100644 (file)
@@ -3,7 +3,6 @@
 
 #include <linux/types.h>
 #include <linux/netlink.h>
-#include <linux/types.h>
 
 struct net_dm_drop_point {
        __u8 pc[8];
index d4a4d98..9f25ab2 100644 (file)
@@ -72,10 +72,6 @@ struct wireless_dev;
 /* Backlog congestion levels */
 #define NET_RX_SUCCESS         0   /* keep 'em coming, baby */
 #define NET_RX_DROP            1  /* packet dropped */
-#define NET_RX_CN_LOW          2   /* storm alert, just in case */
-#define NET_RX_CN_MOD          3   /* Storm on its way! */
-#define NET_RX_CN_HIGH         4   /* The storm is here */
-#define NET_RX_BAD             5  /* packet dropped due to kernel error */
 
 /* NET_XMIT_CN is special. It does not guarantee that this packet is lost. It
  * indicates that the device will soon be dropping packets, or already drops
index dbea93b..e496a2d 100644 (file)
  * @NL80211_CMD_LEAVE_IBSS: Leave the IBSS -- no special arguments, the IBSS is
  *     determined by the network interface.
  *
+ * @NL80211_CMD_TESTMODE: testmode command, takes a wiphy (or ifindex) attribute
+ *     to identify the device, and the TESTDATA blob attribute to pass through
+ *     to the driver.
+ *
+ * @NL80211_CMD_CONNECT: connection request and notification; this command
+ *     requests to connect to a specified network but without separating
+ *     auth and assoc steps. For this, you need to specify the SSID in a
+ *     %NL80211_ATTR_SSID attribute, and can optionally specify the association
+ *     IEs in %NL80211_ATTR_IE, %NL80211_ATTR_AUTH_TYPE, %NL80211_ATTR_MAC,
+ *     %NL80211_ATTR_WIPHY_FREQ and %NL80211_ATTR_CONTROL_PORT.
+ *     It is also sent as an event, with the BSSID and response IEs when the
+ *     connection is established or failed to be established. This can be
+ *     determined by the STATUS_CODE attribute.
+ * @NL80211_CMD_ROAM: request that the card roam (currently not implemented),
+ *     sent as an event when the card/driver roamed by itself.
+ * @NL80211_CMD_DISCONNECT: drop a given connection; also used to notify
+ *     userspace that a connection was dropped by the AP or due to other
+ *     reasons, for this the %NL80211_ATTR_DISCONNECTED_BY_AP and
+ *     %NL80211_ATTR_REASON_CODE attributes are used.
+ *
  * @NL80211_CMD_MAX: highest used command number
  * @__NL80211_CMD_AFTER_LAST: internal use
  */
@@ -310,6 +330,12 @@ enum nl80211_commands {
        NL80211_CMD_JOIN_IBSS,
        NL80211_CMD_LEAVE_IBSS,
 
+       NL80211_CMD_TESTMODE,
+
+       NL80211_CMD_CONNECT,
+       NL80211_CMD_ROAM,
+       NL80211_CMD_DISCONNECT,
+
        /* add new commands above here */
 
        /* used to define NL80211_CMD_MAX below */
@@ -511,6 +537,36 @@ enum nl80211_commands {
  *     authorized by user space. Otherwise, port is marked authorized by
  *     default in station mode.
  *
+ * @NL80211_ATTR_TESTDATA: Testmode data blob, passed through to the driver.
+ *     We recommend using nested, driver-specific attributes within this.
+ *
+ * @NL80211_ATTR_DISCONNECTED_BY_AP: A flag indicating that the DISCONNECT
+ *     event was due to the AP disconnecting the station, and not due to
+ *     a local disconnect request.
+ * @NL80211_ATTR_STATUS_CODE: StatusCode for the %NL80211_CMD_CONNECT
+ *     event (u16)
+ * @NL80211_ATTR_PRIVACY: Flag attribute, used with connect(), indicating
+ *     that protected APs should be used.
+ *
+ * @NL80211_ATTR_CIPHERS_PAIRWISE: Used with CONNECT and ASSOCIATE to
+ *     indicate which unicast key ciphers will be used with the connection
+ *     (an array of u32).
+ * @NL80211_ATTR_CIPHER_GROUP: Used with CONNECT and ASSOCIATE to indicate
+ *     which group key cipher will be used with the connection (a u32).
+ * @NL80211_ATTR_WPA_VERSIONS: Used with CONNECT and ASSOCIATE to indicate
+ *     which WPA version(s) the AP we want to associate with is using
+ *     (a u32 with flags from &enum nl80211_wpa_versions).
+ * @NL80211_ATTR_AKM_SUITES: Used with CONNECT and ASSOCIATE to indicate
+ *     which key management algorithm(s) to use (an array of u32).
+ *
+ * @NL80211_ATTR_REQ_IE: (Re)association request information elements as
+ *     sent out by the card, for ROAM and successful CONNECT events.
+ * @NL80211_ATTR_RESP_IE: (Re)association response information elements as
+ *     sent by peer, for ROAM and successful CONNECT events.
+ *
+ * @NL80211_ATTR_PREV_BSSID: previous BSSID, to be used by in ASSOCIATE
+ *     commands to specify using a reassociate frame
+ *
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @__NL80211_ATTR_AFTER_LAST: internal use
  */
@@ -619,6 +675,23 @@ enum nl80211_attrs {
 
        NL80211_ATTR_CONTROL_PORT,
 
+       NL80211_ATTR_TESTDATA,
+
+       NL80211_ATTR_PRIVACY,
+
+       NL80211_ATTR_DISCONNECTED_BY_AP,
+       NL80211_ATTR_STATUS_CODE,
+
+       NL80211_ATTR_CIPHER_SUITES_PAIRWISE,
+       NL80211_ATTR_CIPHER_SUITE_GROUP,
+       NL80211_ATTR_WPA_VERSIONS,
+       NL80211_ATTR_AKM_SUITES,
+
+       NL80211_ATTR_REQ_IE,
+       NL80211_ATTR_RESP_IE,
+
+       NL80211_ATTR_PREV_BSSID,
+
        /* add attributes here, update the policy in nl80211.c */
 
        __NL80211_ATTR_AFTER_LAST,
@@ -629,6 +702,7 @@ enum nl80211_attrs {
  * Allow user space programs to use #ifdef on new attributes by defining them
  * here
  */
+#define NL80211_CMD_CONNECT NL80211_CMD_CONNECT
 #define NL80211_ATTR_HT_CAPABILITY NL80211_ATTR_HT_CAPABILITY
 #define NL80211_ATTR_BSS_BASIC_RATES NL80211_ATTR_BSS_BASIC_RATES
 #define NL80211_ATTR_WIPHY_TXQ_PARAMS NL80211_ATTR_WIPHY_TXQ_PARAMS
@@ -642,6 +716,10 @@ enum nl80211_attrs {
 #define NL80211_ATTR_SSID NL80211_ATTR_SSID
 #define NL80211_ATTR_AUTH_TYPE NL80211_ATTR_AUTH_TYPE
 #define NL80211_ATTR_REASON_CODE NL80211_ATTR_REASON_CODE
+#define NL80211_ATTR_CIPHER_SUITES_PAIRWISE NL80211_ATTR_CIPHER_SUITES_PAIRWISE
+#define NL80211_ATTR_CIPHER_SUITE_GROUP NL80211_ATTR_CIPHER_SUITE_GROUP
+#define NL80211_ATTR_WPA_VERSIONS NL80211_ATTR_WPA_VERSIONS
+#define NL80211_ATTR_AKM_SUITES NL80211_ATTR_AKM_SUITES
 
 #define NL80211_MAX_SUPP_RATES                 32
 #define NL80211_MAX_SUPP_REG_RULES             32
@@ -650,6 +728,9 @@ enum nl80211_attrs {
 #define NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY    24
 #define NL80211_HT_CAPABILITY_LEN              26
 
+#define NL80211_MAX_NR_CIPHER_SUITES           5
+#define NL80211_MAX_NR_AKM_SUITES              2
+
 /**
  * enum nl80211_iftype - (virtual) interface types
  *
@@ -1194,12 +1275,22 @@ enum nl80211_bss {
  * @NL80211_AUTHTYPE_SHARED_KEY: Shared Key authentication (WEP only)
  * @NL80211_AUTHTYPE_FT: Fast BSS Transition (IEEE 802.11r)
  * @NL80211_AUTHTYPE_NETWORK_EAP: Network EAP (some Cisco APs and mainly LEAP)
+ * @__NL80211_AUTHTYPE_NUM: internal
+ * @NL80211_AUTHTYPE_MAX: maximum valid auth algorithm
+ * @NL80211_AUTHTYPE_AUTOMATIC: determine automatically (if necessary by
+ *     trying multiple times); this is invalid in netlink -- leave out
+ *     the attribute for this on CONNECT commands.
  */
 enum nl80211_auth_type {
        NL80211_AUTHTYPE_OPEN_SYSTEM,
        NL80211_AUTHTYPE_SHARED_KEY,
        NL80211_AUTHTYPE_FT,
        NL80211_AUTHTYPE_NETWORK_EAP,
+
+       /* keep last */
+       __NL80211_AUTHTYPE_NUM,
+       NL80211_AUTHTYPE_MAX = __NL80211_AUTHTYPE_NUM - 1,
+       NL80211_AUTHTYPE_AUTOMATIC
 };
 
 /**
@@ -1224,4 +1315,9 @@ enum nl80211_mfp {
        NL80211_MFP_REQUIRED,
 };
 
+enum nl80211_wpa_versions {
+       NL80211_WPA_VERSION_1 = 1 << 0,
+       NL80211_WPA_VERSION_2 = 1 << 1,
+};
+
 #endif /* __LINUX_NL80211_H */
index a3b0003..73b46b6 100644 (file)
 #define PCI_DEVICE_ID_NETMOS_9835      0x9835
 #define PCI_DEVICE_ID_NETMOS_9845      0x9845
 #define PCI_DEVICE_ID_NETMOS_9855      0x9855
+#define PCI_DEVICE_ID_NETMOS_9901      0x9901
 
 #define PCI_VENDOR_ID_3COM_2           0xa727
 
index 8f921d7..68438e1 100644 (file)
@@ -24,7 +24,8 @@
 
 #define DEFINE_PER_CPU_SECTION(type, name, section)                    \
        __attribute__((__section__(PER_CPU_BASE_SECTION section)))      \
-       PER_CPU_ATTRIBUTES __typeof__(type) per_cpu__##name
+       PER_CPU_ATTRIBUTES PER_CPU_DEF_ATTRIBUTES                       \
+       __typeof__(type) per_cpu__##name
 
 /*
  * Variant on the per-CPU variable declaration/definition theme used for
index 89698d8..5e970c7 100644 (file)
@@ -178,8 +178,10 @@ struct perf_counter_attr {
                                mmap           :  1, /* include mmap data     */
                                comm           :  1, /* include comm data     */
                                freq           :  1, /* use freq, not period  */
+                               inherit_stat   :  1, /* per task counts       */
+                               enable_on_exec :  1, /* next exec enables     */
 
-                               __reserved_1   : 53;
+                               __reserved_1   : 51;
 
        __u32                   wakeup_events;  /* wakeup every n events */
        __u32                   __reserved_2;
@@ -232,6 +234,14 @@ struct perf_counter_mmap_page {
        __u32   lock;                   /* seqlock for synchronization */
        __u32   index;                  /* hardware counter identifier */
        __s64   offset;                 /* add to hardware counter value */
+       __u64   time_enabled;           /* time counter active */
+       __u64   time_running;           /* time counter on cpu */
+
+               /*
+                * Hole for extension of the self monitor capabilities
+                */
+
+       __u64   __reserved[123];        /* align to 1k */
 
        /*
         * Control data for the mmap() data buffer.
@@ -253,7 +263,6 @@ struct perf_counter_mmap_page {
 #define PERF_EVENT_MISC_KERNEL                 (1 << 0)
 #define PERF_EVENT_MISC_USER                   (2 << 0)
 #define PERF_EVENT_MISC_HYPERVISOR             (3 << 0)
-#define PERF_EVENT_MISC_OVERFLOW               (1 << 2)
 
 struct perf_event_header {
        __u32   type;
@@ -327,9 +336,18 @@ enum perf_event_type {
        PERF_EVENT_FORK                 = 7,
 
        /*
-        * When header.misc & PERF_EVENT_MISC_OVERFLOW the event_type field
-        * will be PERF_SAMPLE_*
-        *
+        * struct {
+        *      struct perf_event_header        header;
+        *      u32                             pid, tid;
+        *      u64                             value;
+        *      { u64           time_enabled;   } && PERF_FORMAT_ENABLED
+        *      { u64           time_running;   } && PERF_FORMAT_RUNNING
+        *      { u64           parent_id;      } && PERF_FORMAT_ID
+        * };
+        */
+       PERF_EVENT_READ                 = 8,
+
+       /*
         * struct {
         *      struct perf_event_header        header;
         *
@@ -337,8 +355,9 @@ enum perf_event_type {
         *      { u32                   pid, tid; } && PERF_SAMPLE_TID
         *      { u64                   time;     } && PERF_SAMPLE_TIME
         *      { u64                   addr;     } && PERF_SAMPLE_ADDR
-        *      { u64                   config;   } && PERF_SAMPLE_CONFIG
+        *      { u64                   id;       } && PERF_SAMPLE_ID
         *      { u32                   cpu, res; } && PERF_SAMPLE_CPU
+        *      { u64                   period;   } && PERF_SAMPLE_PERIOD
         *
         *      { u64                   nr;
         *        { u64 id, val; }      cnt[nr];  } && PERF_SAMPLE_GROUP
@@ -347,6 +366,9 @@ enum perf_event_type {
         *        u64                   ips[nr];  } && PERF_SAMPLE_CALLCHAIN
         * };
         */
+       PERF_EVENT_SAMPLE               = 9,
+
+       PERF_EVENT_MAX,                 /* non-ABI */
 };
 
 enum perf_callchain_context {
@@ -582,6 +604,7 @@ struct perf_counter_context {
        int                             nr_counters;
        int                             nr_active;
        int                             is_active;
+       int                             nr_stat;
        atomic_t                        refcount;
        struct task_struct              *task;
 
@@ -669,7 +692,16 @@ static inline int is_software_counter(struct perf_counter *counter)
                (counter->attr.type != PERF_TYPE_HW_CACHE);
 }
 
-extern void perf_swcounter_event(u32, u64, int, struct pt_regs *, u64);
+extern atomic_t perf_swcounter_enabled[PERF_COUNT_SW_MAX];
+
+extern void __perf_swcounter_event(u32, u64, int, struct pt_regs *, u64);
+
+static inline void
+perf_swcounter_event(u32 event, u64 nr, int nmi, struct pt_regs *regs, u64 addr)
+{
+       if (atomic_read(&perf_swcounter_enabled[event]))
+               __perf_swcounter_event(event, nr, nmi, regs, addr);
+}
 
 extern void __perf_counter_mmap(struct vm_area_struct *vma);
 
index 278777f..1020290 100644 (file)
@@ -82,6 +82,20 @@ struct rfkill_event {
        __u8  soft, hard;
 } __packed;
 
+/*
+ * We are planning to be backward and forward compatible with changes
+ * to the event struct, by adding new, optional, members at the end.
+ * When reading an event (whether the kernel from userspace or vice
+ * versa) we need to accept anything that's at least as large as the
+ * version 1 event size, but might be able to accept other sizes in
+ * the future.
+ *
+ * One exception is the kernel -- we already have two event sizes in
+ * that we've made the 'hard' member optional since our only option
+ * is to ignore it anyway.
+ */
+#define RFKILL_EVENT_SIZE_V1   8
+
 /* ioctl for turning off rfkill-input (if present) */
 #define RFKILL_IOC_MAGIC       'R'
 #define RFKILL_IOC_NOINPUT     1
index 4d07542..0085d75 100644 (file)
@@ -349,8 +349,20 @@ extern int mutex_spin_on_owner(struct mutex *lock, struct thread_info *owner);
 struct nsproxy;
 struct user_namespace;
 
-/* Maximum number of active map areas.. This is a random (large) number */
-#define DEFAULT_MAX_MAP_COUNT  65536
+/*
+ * Default maximum number of active map areas, this limits the number of vmas
+ * per mm struct. Users can overwrite this number by sysctl but there is a
+ * problem.
+ *
+ * When a program's coredump is generated as ELF format, a section is created
+ * per a vma. In ELF, the number of sections is represented in unsigned short.
+ * This means the number of sections should be smaller than 65535 at coredump.
+ * Because the kernel adds some informative sections to a image of program at
+ * generating coredump, we need some margin. The number of extra sections is
+ * 1-3 now and depends on arch. We use "5" as safe margin, here.
+ */
+#define MAPCOUNT_ELF_CORE_MARGIN       (5)
+#define DEFAULT_MAX_MAP_COUNT  (USHORT_MAX - MAPCOUNT_ELF_CORE_MARGIN)
 
 extern int sysctl_max_map_count;
 
index 9c4cd27..c47c4b4 100644 (file)
@@ -80,6 +80,8 @@ struct spi_device {
 #define        SPI_LSB_FIRST   0x08                    /* per-word bits-on-wire */
 #define        SPI_3WIRE       0x10                    /* SI/SO signals shared */
 #define        SPI_LOOP        0x20                    /* loopback mode */
+#define        SPI_NO_CS       0x40                    /* 1 dev/bus, no chipselect */
+#define        SPI_READY       0x80                    /* slave pulls low to pause */
        u8                      bits_per_word;
        int                     irq;
        void                    *controller_state;
@@ -248,6 +250,10 @@ struct spi_master {
        /* spi_device.mode flags understood by this controller driver */
        u16                     mode_bits;
 
+       /* other constraints relevant to this driver */
+       u16                     flags;
+#define SPI_MASTER_HALF_DUPLEX BIT(0)          /* can't do full duplex */
+
        /* Setup mode and clock, etc (spi driver may call many times).
         *
         * IMPORTANT:  this may be called when transfers to another
index 95251cc..bf0570a 100644 (file)
@@ -40,6 +40,8 @@
 #define SPI_LSB_FIRST          0x08
 #define SPI_3WIRE              0x10
 #define SPI_LOOP               0x20
+#define SPI_NO_CS              0x40
+#define SPI_READY              0x80
 
 /*---------------------------------------------------------------------------*/
 
index ccf882e..be62ec2 100644 (file)
@@ -190,6 +190,8 @@ extern unsigned long get_next_timer_interrupt(unsigned long now);
  */
 #ifdef CONFIG_TIMER_STATS
 
+extern int timer_stats_active;
+
 #define TIMER_STATS_FLAG_DEFERRABLE    0x1
 
 extern void init_timer_stats(void);
@@ -203,6 +205,8 @@ extern void __timer_stats_timer_set_start_info(struct timer_list *timer,
 
 static inline void timer_stats_timer_set_start_info(struct timer_list *timer)
 {
+       if (likely(!timer_stats_active))
+               return;
        __timer_stats_timer_set_start_info(timer, __builtin_return_address(0));
 }
 
index bea4694..3d92396 100644 (file)
@@ -209,5 +209,7 @@ struct sockaddr_tipc {
 #define TIPC_SRC_DROPPABLE     128     /* Default: 0 (resend congested msg) */
 #define TIPC_DEST_DROPPABLE    129     /* Default: based on socket type */
 #define TIPC_CONN_TIMEOUT      130     /* Default: 8000 (ms)  */
+#define TIPC_NODE_RECVQ_DEPTH  131     /* Default: none (read only) */
+#define TIPC_SOCK_RECVQ_DEPTH  132     /* Default: none (read only) */
 
 #endif
index 310e18a..7c17b2e 100644 (file)
@@ -97,6 +97,9 @@ struct driver_info {
        /* reset device ... can sleep */
        int     (*reset)(struct usbnet *);
 
+       /* stop device ... can sleep */
+       int     (*stop)(struct usbnet *);
+
        /* see if peer is connected ... can sleep */
        int     (*check_connect)(struct usbnet *);
 
index cb24204..5b4c6c7 100644 (file)
@@ -1132,6 +1132,14 @@ struct __compat_iw_event {
 };
 #define IW_EV_COMPAT_LCP_LEN offsetof(struct __compat_iw_event, pointer)
 #define IW_EV_COMPAT_POINT_OFF offsetof(struct compat_iw_point, length)
+
+/* Size of the various events for compat */
+#define IW_EV_COMPAT_CHAR_LEN  (IW_EV_COMPAT_LCP_LEN + IFNAMSIZ)
+#define IW_EV_COMPAT_UINT_LEN  (IW_EV_COMPAT_LCP_LEN + sizeof(__u32))
+#define IW_EV_COMPAT_FREQ_LEN  (IW_EV_COMPAT_LCP_LEN + sizeof(struct iw_freq))
+#define IW_EV_COMPAT_PARAM_LEN (IW_EV_COMPAT_LCP_LEN + sizeof(struct iw_param))
+#define IW_EV_COMPAT_ADDR_LEN  (IW_EV_COMPAT_LCP_LEN + sizeof(struct sockaddr))
+#define IW_EV_COMPAT_QUAL_LEN  (IW_EV_COMPAT_LCP_LEN + sizeof(struct iw_quality))
 #define IW_EV_COMPAT_POINT_LEN \
        (IW_EV_COMPAT_LCP_LEN + sizeof(struct compat_iw_point) - \
         IW_EV_COMPAT_POINT_OFF)
index 1a21895..83c2c72 100644 (file)
@@ -555,6 +555,7 @@ struct cfg80211_scan_request {
        /* internal */
        struct wiphy *wiphy;
        int ifidx;
+       bool aborted;
 };
 
 /**
@@ -584,7 +585,6 @@ enum cfg80211_signal_type {
  *     is no guarantee that these are well-formed!)
  * @len_information_elements: total length of the information elements
  * @signal: signal strength value (type depends on the wiphy's signal_type)
- * @hold: BSS should not expire
  * @free_priv: function pointer to free private data
  * @priv: private area for driver use, has at least wiphy->bss_priv_size bytes
  */
@@ -605,37 +605,54 @@ struct cfg80211_bss {
 };
 
 /**
+ * ieee80211_bss_get_ie - find IE with given ID
+ * @bss: the bss to search
+ * @ie: the IE ID
+ * Returns %NULL if not found.
+ */
+const u8 *ieee80211_bss_get_ie(struct cfg80211_bss *bss, u8 ie);
+
+
+/**
+ * struct cfg80211_crypto_settings - Crypto settings
+ * @wpa_versions: indicates which, if any, WPA versions are enabled
+ *     (from enum nl80211_wpa_versions)
+ * @cipher_group: group key cipher suite (or 0 if unset)
+ * @n_ciphers_pairwise: number of AP supported unicast ciphers
+ * @ciphers_pairwise: unicast key cipher suites
+ * @n_akm_suites: number of AKM suites
+ * @akm_suites: AKM suites
+ * @control_port: Whether user space controls IEEE 802.1X port, i.e.,
+ *     sets/clears %NL80211_STA_FLAG_AUTHORIZED. If true, the driver is
+ *     required to assume that the port is unauthorized until authorized by
+ *     user space. Otherwise, port is marked authorized by default.
+ */
+struct cfg80211_crypto_settings {
+       u32 wpa_versions;
+       u32 cipher_group;
+       int n_ciphers_pairwise;
+       u32 ciphers_pairwise[NL80211_MAX_NR_CIPHER_SUITES];
+       int n_akm_suites;
+       u32 akm_suites[NL80211_MAX_NR_AKM_SUITES];
+       bool control_port;
+};
+
+/**
  * struct cfg80211_auth_request - Authentication request data
  *
  * This structure provides information needed to complete IEEE 802.11
  * authentication.
- * NOTE: This structure will likely change when more code from mac80211 is
- * moved into cfg80211 so that non-mac80211 drivers can benefit from it, too.
- * Before using this in a driver that does not use mac80211, it would be better
- * to check the status of that work and better yet, volunteer to work on it.
- *
- * @chan: The channel to use or %NULL if not specified (auto-select based on
- *     scan results)
- * @peer_addr: The address of the peer STA (AP BSSID in infrastructure case);
- *     this field is required to be present; if the driver wants to help with
- *     BSS selection, it should use (yet to be added) MLME event to allow user
- *     space SME to be notified of roaming candidate, so that the SME can then
- *     use the authentication request with the recommended BSSID and whatever
- *     other data may be needed for authentication/association
- * @ssid: SSID or %NULL if not yet available
- * @ssid_len: Length of ssid in octets
+ *
+ * @bss: The BSS to authenticate with.
  * @auth_type: Authentication type (algorithm)
  * @ie: Extra IEs to add to Authentication frame or %NULL
  * @ie_len: Length of ie buffer in octets
  */
 struct cfg80211_auth_request {
-       struct ieee80211_channel *chan;
-       u8 *peer_addr;
-       const u8 *ssid;
-       size_t ssid_len;
-       enum nl80211_auth_type auth_type;
+       struct cfg80211_bss *bss;
        const u8 *ie;
        size_t ie_len;
+       enum nl80211_auth_type auth_type;
 };
 
 /**
@@ -643,35 +660,19 @@ struct cfg80211_auth_request {
  *
  * This structure provides information needed to complete IEEE 802.11
  * (re)association.
- * NOTE: This structure will likely change when more code from mac80211 is
- * moved into cfg80211 so that non-mac80211 drivers can benefit from it, too.
- * Before using this in a driver that does not use mac80211, it would be better
- * to check the status of that work and better yet, volunteer to work on it.
- *
- * @chan: The channel to use or %NULL if not specified (auto-select based on
- *     scan results)
- * @peer_addr: The address of the peer STA (AP BSSID); this field is required
- *     to be present and the STA must be in State 2 (authenticated) with the
- *     peer STA
- * @ssid: SSID
- * @ssid_len: Length of ssid in octets
+ * @bss: The BSS to associate with.
  * @ie: Extra IEs to add to (Re)Association Request frame or %NULL
  * @ie_len: Length of ie buffer in octets
  * @use_mfp: Use management frame protection (IEEE 802.11w) in this association
- * @control_port: Whether user space controls IEEE 802.1X port, i.e.,
- *     sets/clears %NL80211_STA_FLAG_AUTHORIZED. If true, the driver is
- *     required to assume that the port is unauthorized until authorized by
- *     user space. Otherwise, port is marked authorized by default.
+ * @crypto: crypto settings
+ * @prev_bssid: previous BSSID, if not %NULL use reassociate frame
  */
 struct cfg80211_assoc_request {
-       struct ieee80211_channel *chan;
-       u8 *peer_addr;
-       const u8 *ssid;
-       size_t ssid_len;
-       const u8 *ie;
+       struct cfg80211_bss *bss;
+       const u8 *ie, *prev_bssid;
        size_t ie_len;
+       struct cfg80211_crypto_settings crypto;
        bool use_mfp;
-       bool control_port;
 };
 
 /**
@@ -680,16 +681,16 @@ struct cfg80211_assoc_request {
  * This structure provides information needed to complete IEEE 802.11
  * deauthentication.
  *
- * @peer_addr: The address of the peer STA (AP BSSID); this field is required
- *     to be present and the STA must be authenticated with the peer STA
+ * @bss: the BSS to deauthenticate from
  * @ie: Extra IEs to add to Deauthentication frame or %NULL
  * @ie_len: Length of ie buffer in octets
+ * @reason_code: The reason code for the deauthentication
  */
 struct cfg80211_deauth_request {
-       u8 *peer_addr;
-       u16 reason_code;
+       struct cfg80211_bss *bss;
        const u8 *ie;
        size_t ie_len;
+       u16 reason_code;
 };
 
 /**
@@ -698,16 +699,16 @@ struct cfg80211_deauth_request {
  * This structure provides information needed to complete IEEE 802.11
  * disassocation.
  *
- * @peer_addr: The address of the peer STA (AP BSSID); this field is required
- *     to be present and the STA must be associated with the peer STA
+ * @bss: the BSS to disassociate from
  * @ie: Extra IEs to add to Disassociation frame or %NULL
  * @ie_len: Length of ie buffer in octets
+ * @reason_code: The reason code for the disassociation
  */
 struct cfg80211_disassoc_request {
-       u8 *peer_addr;
-       u16 reason_code;
+       struct cfg80211_bss *bss;
        const u8 *ie;
        size_t ie_len;
+       u16 reason_code;
 };
 
 /**
@@ -738,6 +739,36 @@ struct cfg80211_ibss_params {
 };
 
 /**
+ * struct cfg80211_connect_params - Connection parameters
+ *
+ * This structure provides information needed to complete IEEE 802.11
+ * authentication and association.
+ *
+ * @channel: The channel to use or %NULL if not specified (auto-select based
+ *     on scan results)
+ * @bssid: The AP BSSID or %NULL if not specified (auto-select based on scan
+ *     results)
+ * @ssid: SSID
+ * @ssid_len: Length of ssid in octets
+ * @auth_type: Authentication type (algorithm)
+ * @assoc_ie: IEs for association request
+ * @assoc_ie_len: Length of assoc_ie in octets
+ * @privacy: indicates whether privacy-enabled APs should be used
+ * @crypto: crypto settings
+ */
+struct cfg80211_connect_params {
+       struct ieee80211_channel *channel;
+       u8 *bssid;
+       u8 *ssid;
+       size_t ssid_len;
+       enum nl80211_auth_type auth_type;
+       u8 *ie;
+       size_t ie_len;
+       bool privacy;
+       struct cfg80211_crypto_settings crypto;
+};
+
+/**
  * enum wiphy_params_flags - set_wiphy_params bitfield values
  * WIPHY_PARAM_RETRY_SHORT: wiphy->retry_short has changed
  * WIPHY_PARAM_RETRY_LONG: wiphy->retry_long has changed
@@ -764,6 +795,26 @@ enum tx_power_setting {
        TX_POWER_FIXED,
 };
 
+/*
+ * cfg80211_bitrate_mask - masks for bitrate control
+ */
+struct cfg80211_bitrate_mask {
+/*
+ * As discussed in Berlin, this struct really
+ * should look like this:
+
+       struct {
+               u32 legacy;
+               u8 mcs[IEEE80211_HT_MCS_MASK_LEN];
+       } control[IEEE80211_NUM_BANDS];
+
+ * Since we can always fix in-kernel users, let's keep
+ * it simpler for now:
+ */
+       u32 fixed;   /* fixed bitrate, 0 == not fixed */
+       u32 maxrate; /* in kbps, 0 == no limit */
+};
+
 /**
  * struct cfg80211_ops - backend description for wireless configuration
  *
@@ -841,6 +892,12 @@ enum tx_power_setting {
  * @deauth: Request to deauthenticate from the specified peer
  * @disassoc: Request to disassociate from the specified peer
  *
+ * @connect: Connect to the ESS with the specified parameters. When connected,
+ *     call cfg80211_connect_result() with status code %WLAN_STATUS_SUCCESS.
+ *     If the connection fails for some reason, call cfg80211_connect_result()
+ *     with the status from the AP.
+ * @disconnect: Disconnect from the BSS/ESS.
+ *
  * @join_ibss: Join the specified IBSS (or create if necessary). Once done, call
  *     cfg80211_ibss_joined(), also call that function when changing BSSID due
  *     to a merge.
@@ -857,6 +914,8 @@ enum tx_power_setting {
  *
  * @rfkill_poll: polls the hw rfkill line, use cfg80211 reporting
  *     functions to adjust rfkill hw state
+ *
+ * @testmode_cmd: run a test mode command
  */
 struct cfg80211_ops {
        int     (*suspend)(struct wiphy *wiphy);
@@ -866,7 +925,8 @@ struct cfg80211_ops {
                                    enum nl80211_iftype type, u32 *flags,
                                    struct vif_params *params);
        int     (*del_virtual_intf)(struct wiphy *wiphy, int ifindex);
-       int     (*change_virtual_intf)(struct wiphy *wiphy, int ifindex,
+       int     (*change_virtual_intf)(struct wiphy *wiphy,
+                                      struct net_device *dev,
                                       enum nl80211_iftype type, u32 *flags,
                                       struct vif_params *params);
 
@@ -939,9 +999,16 @@ struct cfg80211_ops {
        int     (*assoc)(struct wiphy *wiphy, struct net_device *dev,
                         struct cfg80211_assoc_request *req);
        int     (*deauth)(struct wiphy *wiphy, struct net_device *dev,
-                         struct cfg80211_deauth_request *req);
+                         struct cfg80211_deauth_request *req,
+                         void *cookie);
        int     (*disassoc)(struct wiphy *wiphy, struct net_device *dev,
-                           struct cfg80211_disassoc_request *req);
+                           struct cfg80211_disassoc_request *req,
+                           void *cookie);
+
+       int     (*connect)(struct wiphy *wiphy, struct net_device *dev,
+                          struct cfg80211_connect_params *sme);
+       int     (*disconnect)(struct wiphy *wiphy, struct net_device *dev,
+                             u16 reason_code);
 
        int     (*join_ibss)(struct wiphy *wiphy, struct net_device *dev,
                             struct cfg80211_ibss_params *params);
@@ -953,7 +1020,23 @@ struct cfg80211_ops {
                                enum tx_power_setting type, int dbm);
        int     (*get_tx_power)(struct wiphy *wiphy, int *dbm);
 
+       int     (*set_wds_peer)(struct wiphy *wiphy, struct net_device *dev,
+                               u8 *addr);
+
        void    (*rfkill_poll)(struct wiphy *wiphy);
+
+#ifdef CONFIG_NL80211_TESTMODE
+       int     (*testmode_cmd)(struct wiphy *wiphy, void *data, int len);
+#endif
+
+       int     (*set_bitrate_mask)(struct wiphy *wiphy,
+                                   struct net_device *dev,
+                                   const u8 *peer,
+                                   const struct cfg80211_bitrate_mask *mask);
+
+       /* some temporary stuff to finish wext */
+       int     (*set_power_mgmt)(struct wiphy *wiphy, struct net_device *dev,
+                                 bool enabled, int timeout);
 };
 
 /*
@@ -1058,6 +1141,17 @@ static inline void *wiphy_priv(struct wiphy *wiphy)
 }
 
 /**
+ * priv_to_wiphy - return the wiphy containing the priv
+ *
+ * @priv: a pointer previously returned by wiphy_priv
+ */
+static inline struct wiphy *priv_to_wiphy(void *priv)
+{
+       BUG_ON(!priv);
+       return container_of(priv, struct wiphy, priv);
+}
+
+/**
  * set_wiphy_dev - set device pointer for wiphy
  *
  * @wiphy: The wiphy whose device to bind
@@ -1129,6 +1223,12 @@ extern void wiphy_unregister(struct wiphy *wiphy);
  */
 extern void wiphy_free(struct wiphy *wiphy);
 
+/* internal struct */
+struct cfg80211_conn;
+struct cfg80211_internal_bss;
+
+#define MAX_AUTH_BSSES         4
+
 /**
  * struct wireless_dev - wireless per-netdev state
  *
@@ -1152,22 +1252,41 @@ struct wireless_dev {
        struct wiphy *wiphy;
        enum nl80211_iftype iftype;
 
-       /* private to the generic wireless code */
+       /* the remainder of this struct should be private to cfg80211 */
        struct list_head list;
        struct net_device *netdev;
 
-       /* currently used for IBSS - might be rearranged in the future */
-       struct cfg80211_bss *current_bss;
-       u8 bssid[ETH_ALEN];
+       struct mutex mtx;
+
+       /* currently used for IBSS and SME - might be rearranged later */
        u8 ssid[IEEE80211_MAX_SSID_LEN];
        u8 ssid_len;
+       enum {
+               CFG80211_SME_IDLE,
+               CFG80211_SME_CONNECTING,
+               CFG80211_SME_CONNECTED,
+       } sme_state;
+       struct cfg80211_conn *conn;
+
+       struct list_head event_list;
+       spinlock_t event_lock;
+
+       struct cfg80211_internal_bss *authtry_bsses[MAX_AUTH_BSSES];
+       struct cfg80211_internal_bss *auth_bsses[MAX_AUTH_BSSES];
+       struct cfg80211_internal_bss *current_bss; /* associated / joined */
 
 #ifdef CONFIG_WIRELESS_EXT
        /* wext data */
        struct {
                struct cfg80211_ibss_params ibss;
+               struct cfg80211_connect_params connect;
+               u8 *ie;
+               size_t ie_len;
                u8 bssid[ETH_ALEN];
+               u8 ssid[IEEE80211_MAX_SSID_LEN];
                s8 default_key, default_mgmt_key;
+               bool ps;
+               int ps_timeout;
        } wext;
 #endif
 };
@@ -1447,9 +1566,44 @@ int cfg80211_ibss_wext_giwap(struct net_device *dev,
                             struct iw_request_info *info,
                             struct sockaddr *ap_addr, char *extra);
 
+int cfg80211_mgd_wext_siwfreq(struct net_device *dev,
+                             struct iw_request_info *info,
+                             struct iw_freq *freq, char *extra);
+int cfg80211_mgd_wext_giwfreq(struct net_device *dev,
+                             struct iw_request_info *info,
+                             struct iw_freq *freq, char *extra);
+int cfg80211_mgd_wext_siwessid(struct net_device *dev,
+                              struct iw_request_info *info,
+                              struct iw_point *data, char *ssid);
+int cfg80211_mgd_wext_giwessid(struct net_device *dev,
+                              struct iw_request_info *info,
+                              struct iw_point *data, char *ssid);
+int cfg80211_mgd_wext_siwap(struct net_device *dev,
+                           struct iw_request_info *info,
+                           struct sockaddr *ap_addr, char *extra);
+int cfg80211_mgd_wext_giwap(struct net_device *dev,
+                           struct iw_request_info *info,
+                           struct sockaddr *ap_addr, char *extra);
+int cfg80211_wext_siwgenie(struct net_device *dev,
+                          struct iw_request_info *info,
+                          struct iw_point *data, char *extra);
+int cfg80211_wext_siwauth(struct net_device *dev,
+                         struct iw_request_info *info,
+                         struct iw_param *data, char *extra);
+int cfg80211_wext_giwauth(struct net_device *dev,
+                         struct iw_request_info *info,
+                         struct iw_param *data, char *extra);
+
 struct ieee80211_channel *cfg80211_wext_freq(struct wiphy *wiphy,
                                             struct iw_freq *freq);
 
+int cfg80211_wext_siwrate(struct net_device *dev,
+                         struct iw_request_info *info,
+                         struct iw_param *rate, char *extra);
+int cfg80211_wext_giwrate(struct net_device *dev,
+                         struct iw_request_info *info,
+                         struct iw_param *rate, char *extra);
+
 int cfg80211_wext_siwrts(struct net_device *dev,
                         struct iw_request_info *info,
                         struct iw_param *rts, char *extra);
@@ -1483,6 +1637,21 @@ int cfg80211_wext_siwtxpower(struct net_device *dev,
 int cfg80211_wext_giwtxpower(struct net_device *dev,
                             struct iw_request_info *info,
                             union iwreq_data *data, char *keybuf);
+struct iw_statistics *cfg80211_wireless_stats(struct net_device *dev);
+
+int cfg80211_wext_siwpower(struct net_device *dev,
+                          struct iw_request_info *info,
+                          struct iw_param *wrq, char *extra);
+int cfg80211_wext_giwpower(struct net_device *dev,
+                          struct iw_request_info *info,
+                          struct iw_param *wrq, char *extra);
+
+int cfg80211_wds_wext_siwap(struct net_device *dev,
+                           struct iw_request_info *info,
+                           struct sockaddr *addr, char *extra);
+int cfg80211_wds_wext_giwap(struct net_device *dev,
+                           struct iw_request_info *info,
+                           struct sockaddr *addr, char *extra);
 
 /*
  * callbacks for asynchronous cfg80211 methods, notification
@@ -1564,7 +1733,7 @@ void cfg80211_unlink_bss(struct wiphy *wiphy, struct cfg80211_bss *bss);
  * This function is called whenever an authentication has been processed in
  * station mode. The driver is required to call either this function or
  * cfg80211_send_auth_timeout() to indicate the result of cfg80211_ops::auth()
- * call.
+ * call. This function may sleep.
  */
 void cfg80211_send_rx_auth(struct net_device *dev, const u8 *buf, size_t len);
 
@@ -1572,6 +1741,8 @@ void cfg80211_send_rx_auth(struct net_device *dev, const u8 *buf, size_t len);
  * cfg80211_send_auth_timeout - notification of timed out authentication
  * @dev: network device
  * @addr: The MAC address of the device with which the authentication timed out
+ *
+ * This function may sleep.
  */
 void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr);
 
@@ -1584,7 +1755,7 @@ void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr);
  * This function is called whenever a (re)association response has been
  * processed in station mode. The driver is required to call either this
  * function or cfg80211_send_assoc_timeout() to indicate the result of
- * cfg80211_ops::assoc() call.
+ * cfg80211_ops::assoc() call. This function may sleep.
  */
 void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len);
 
@@ -1592,6 +1763,8 @@ void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len);
  * cfg80211_send_assoc_timeout - notification of timed out association
  * @dev: network device
  * @addr: The MAC address of the device with which the association timed out
+ *
+ * This function may sleep.
  */
 void cfg80211_send_assoc_timeout(struct net_device *dev, const u8 *addr);
 
@@ -1600,41 +1773,30 @@ void cfg80211_send_assoc_timeout(struct net_device *dev, const u8 *addr);
  * @dev: network device
  * @buf: deauthentication frame (header + body)
  * @len: length of the frame data
+ * @cookie: cookie from ->deauth if called within that callback,
+ *     %NULL otherwise
  *
  * This function is called whenever deauthentication has been processed in
  * station mode. This includes both received deauthentication frames and
- * locally generated ones.
+ * locally generated ones. This function may sleep.
  */
-void cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len);
+void cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len,
+                         void *cookie);
 
 /**
  * cfg80211_send_disassoc - notification of processed disassociation
  * @dev: network device
  * @buf: disassociation response frame (header + body)
  * @len: length of the frame data
+ * @cookie: cookie from ->disassoc if called within that callback,
+ *     %NULL otherwise
  *
  * This function is called whenever disassociation has been processed in
  * station mode. This includes both received disassociation frames and locally
- * generated ones.
+ * generated ones. This function may sleep.
  */
-void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len);
-
-/**
- * cfg80211_hold_bss - exclude bss from expiration
- * @bss: bss which should not expire
- *
- * In a case when the BSS is not updated but it shouldn't expire this
- * function can be used to mark the BSS to be excluded from expiration.
- */
-void cfg80211_hold_bss(struct cfg80211_bss *bss);
-
-/**
- * cfg80211_unhold_bss - remove expiration exception from the BSS
- * @bss: bss which can expire again
- *
- * This function marks the BSS to be expirable again.
- */
-void cfg80211_unhold_bss(struct cfg80211_bss *bss);
+void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len,
+                           void *cookie);
 
 /**
  * cfg80211_michael_mic_failure - notification of Michael MIC failure (TKIP)
@@ -1643,6 +1805,7 @@ void cfg80211_unhold_bss(struct cfg80211_bss *bss);
  * @key_type: The key type that the received frame used
  * @key_id: Key identifier (0..3)
  * @tsc: The TSC value of the frame that generated the MIC failure (6 octets)
+ * @gfp: allocation flags
  *
  * This function is called whenever the local MAC detects a MIC failure in a
  * received frame. This matches with MLME-MICHAELMICFAILURE.indication()
@@ -1650,7 +1813,7 @@ void cfg80211_unhold_bss(struct cfg80211_bss *bss);
  */
 void cfg80211_michael_mic_failure(struct net_device *dev, const u8 *addr,
                                  enum nl80211_key_type key_type, int key_id,
-                                 const u8 *tsc);
+                                 const u8 *tsc, gfp_t gfp);
 
 /**
  * cfg80211_ibss_joined - notify cfg80211 that device joined an IBSS
@@ -1687,4 +1850,137 @@ void wiphy_rfkill_start_polling(struct wiphy *wiphy);
  */
 void wiphy_rfkill_stop_polling(struct wiphy *wiphy);
 
+#ifdef CONFIG_NL80211_TESTMODE
+/**
+ * cfg80211_testmode_alloc_reply_skb - allocate testmode reply
+ * @wiphy: the wiphy
+ * @approxlen: an upper bound of the length of the data that will
+ *     be put into the skb
+ *
+ * This function allocates and pre-fills an skb for a reply to
+ * the testmode command. Since it is intended for a reply, calling
+ * it outside of the @testmode_cmd operation is invalid.
+ *
+ * The returned skb (or %NULL if any errors happen) is pre-filled
+ * with the wiphy index and set up in a way that any data that is
+ * put into the skb (with skb_put(), nla_put() or similar) will end
+ * up being within the %NL80211_ATTR_TESTDATA attribute, so all that
+ * needs to be done with the skb is adding data for the corresponding
+ * userspace tool which can then read that data out of the testdata
+ * attribute. You must not modify the skb in any other way.
+ *
+ * When done, call cfg80211_testmode_reply() with the skb and return
+ * its error code as the result of the @testmode_cmd operation.
+ */
+struct sk_buff *cfg80211_testmode_alloc_reply_skb(struct wiphy *wiphy,
+                                                 int approxlen);
+
+/**
+ * cfg80211_testmode_reply - send the reply skb
+ * @skb: The skb, must have been allocated with
+ *     cfg80211_testmode_alloc_reply_skb()
+ *
+ * Returns an error code or 0 on success, since calling this
+ * function will usually be the last thing before returning
+ * from the @testmode_cmd you should return the error code.
+ * Note that this function consumes the skb regardless of the
+ * return value.
+ */
+int cfg80211_testmode_reply(struct sk_buff *skb);
+
+/**
+ * cfg80211_testmode_alloc_event_skb - allocate testmode event
+ * @wiphy: the wiphy
+ * @approxlen: an upper bound of the length of the data that will
+ *     be put into the skb
+ * @gfp: allocation flags
+ *
+ * This function allocates and pre-fills an skb for an event on the
+ * testmode multicast group.
+ *
+ * The returned skb (or %NULL if any errors happen) is set up in the
+ * same way as with cfg80211_testmode_alloc_reply_skb() but prepared
+ * for an event. As there, you should simply add data to it that will
+ * then end up in the %NL80211_ATTR_TESTDATA attribute. Again, you must
+ * not modify the skb in any other way.
+ *
+ * When done filling the skb, call cfg80211_testmode_event() with the
+ * skb to send the event.
+ */
+struct sk_buff *cfg80211_testmode_alloc_event_skb(struct wiphy *wiphy,
+                                                 int approxlen, gfp_t gfp);
+
+/**
+ * cfg80211_testmode_event - send the event
+ * @skb: The skb, must have been allocated with
+ *     cfg80211_testmode_alloc_event_skb()
+ * @gfp: allocation flags
+ *
+ * This function sends the given @skb, which must have been allocated
+ * by cfg80211_testmode_alloc_event_skb(), as an event. It always
+ * consumes it.
+ */
+void cfg80211_testmode_event(struct sk_buff *skb, gfp_t gfp);
+
+#define CFG80211_TESTMODE_CMD(cmd)     .testmode_cmd = (cmd),
+#else
+#define CFG80211_TESTMODE_CMD(cmd)
+#endif
+
+/**
+ * cfg80211_connect_result - notify cfg80211 of connection result
+ *
+ * @dev: network device
+ * @bssid: the BSSID of the AP
+ * @req_ie: association request IEs (maybe be %NULL)
+ * @req_ie_len: association request IEs length
+ * @resp_ie: association response IEs (may be %NULL)
+ * @resp_ie_len: assoc response IEs length
+ * @status: status code, 0 for successful connection, use
+ *     %WLAN_STATUS_UNSPECIFIED_FAILURE if your device cannot give you
+ *     the real status code for failures.
+ * @gfp: allocation flags
+ *
+ * It should be called by the underlying driver whenever connect() has
+ * succeeded.
+ */
+void cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
+                            const u8 *req_ie, size_t req_ie_len,
+                            const u8 *resp_ie, size_t resp_ie_len,
+                            u16 status, gfp_t gfp);
+
+/**
+ * cfg80211_roamed - notify cfg80211 of roaming
+ *
+ * @dev: network device
+ * @bssid: the BSSID of the new AP
+ * @req_ie: association request IEs (maybe be %NULL)
+ * @req_ie_len: association request IEs length
+ * @resp_ie: association response IEs (may be %NULL)
+ * @resp_ie_len: assoc response IEs length
+ * @gfp: allocation flags
+ *
+ * It should be called by the underlying driver whenever it roamed
+ * from one AP to another while connected.
+ */
+void cfg80211_roamed(struct net_device *dev, const u8 *bssid,
+                    const u8 *req_ie, size_t req_ie_len,
+                    const u8 *resp_ie, size_t resp_ie_len, gfp_t gfp);
+
+/**
+ * cfg80211_disconnected - notify cfg80211 that connection was dropped
+ *
+ * @dev: network device
+ * @ie: information elements of the deauth/disassoc frame (may be %NULL)
+ * @ie_len: length of IEs
+ * @reason: reason code for the disconnection, set it to 0 if unknown
+ * @gfp: allocation flags
+ *
+ * After it calls this function, the driver should enter an idle state
+ * and not try to connect to any AP any more.
+ */
+void cfg80211_disconnected(struct net_device *dev, u16 reason,
+                          u8 *ie, size_t ie_len, gfp_t gfp);
+
+
 #endif /* __NET_CFG80211_H */
index 1b0e3ee..2a1c068 100644 (file)
@@ -3,6 +3,7 @@
 
 #include <linux/genetlink.h>
 #include <net/netlink.h>
+#include <net/net_namespace.h>
 
 /**
  * struct genl_multicast_group - generic netlink multicast group
@@ -27,6 +28,8 @@ struct genl_multicast_group
  * @name: name of family
  * @version: protocol version
  * @maxattr: maximum number of attributes supported
+ * @netnsok: set to true if the family can handle network
+ *     namespaces and should be presented in all of them
  * @attrbuf: buffer to store parsed attributes
  * @ops_list: list of all assigned operations
  * @family_list: family list
@@ -39,6 +42,7 @@ struct genl_family
        char                    name[GENL_NAMSIZ];
        unsigned int            version;
        unsigned int            maxattr;
+       bool                    netnsok;
        struct nlattr **        attrbuf;        /* private */
        struct list_head        ops_list;       /* private */
        struct list_head        family_list;    /* private */
@@ -62,8 +66,32 @@ struct genl_info
        struct genlmsghdr *     genlhdr;
        void *                  userhdr;
        struct nlattr **        attrs;
+#ifdef CONFIG_NET_NS
+       struct net *            _net;
+#endif
 };
 
+#ifdef CONFIG_NET_NS
+static inline struct net *genl_info_net(struct genl_info *info)
+{
+       return info->_net;
+}
+
+static inline void genl_info_net_set(struct genl_info *info, struct net *net)
+{
+       info->_net = net;
+}
+#else
+static inline struct net *genl_info_net(struct genl_info *info)
+{
+       return &init_net;
+}
+
+static inline void genl_info_net_set(struct genl_info *info, struct net *net)
+{
+}
+#endif
+
 /**
  * struct genl_ops - generic netlink operations
  * @cmd: command identifier
@@ -98,8 +126,6 @@ extern int genl_register_mc_group(struct genl_family *family,
 extern void genl_unregister_mc_group(struct genl_family *family,
                                     struct genl_multicast_group *grp);
 
-extern struct sock *genl_sock;
-
 /**
  * genlmsg_put - Add generic netlink header to netlink message
  * @skb: socket buffer holding the message
@@ -170,7 +196,21 @@ static inline void genlmsg_cancel(struct sk_buff *skb, void *hdr)
 }
 
 /**
- * genlmsg_multicast - multicast a netlink message
+ * genlmsg_multicast_netns - multicast a netlink message to a specific netns
+ * @net: the net namespace
+ * @skb: netlink message as socket buffer
+ * @pid: own netlink pid to avoid sending to yourself
+ * @group: multicast group id
+ * @flags: allocation flags
+ */
+static inline int genlmsg_multicast_netns(struct net *net, struct sk_buff *skb,
+                                         u32 pid, unsigned int group, gfp_t flags)
+{
+       return nlmsg_multicast(net->genl_sock, skb, pid, group, flags);
+}
+
+/**
+ * genlmsg_multicast - multicast a netlink message to the default netns
  * @skb: netlink message as socket buffer
  * @pid: own netlink pid to avoid sending to yourself
  * @group: multicast group id
@@ -179,17 +219,29 @@ static inline void genlmsg_cancel(struct sk_buff *skb, void *hdr)
 static inline int genlmsg_multicast(struct sk_buff *skb, u32 pid,
                                    unsigned int group, gfp_t flags)
 {
-       return nlmsg_multicast(genl_sock, skb, pid, group, flags);
+       return genlmsg_multicast_netns(&init_net, skb, pid, group, flags);
 }
 
 /**
+ * genlmsg_multicast_allns - multicast a netlink message to all net namespaces
+ * @skb: netlink message as socket buffer
+ * @pid: own netlink pid to avoid sending to yourself
+ * @group: multicast group id
+ * @flags: allocation flags
+ *
+ * This function must hold the RTNL or rcu_read_lock().
+ */
+int genlmsg_multicast_allns(struct sk_buff *skb, u32 pid,
+                           unsigned int group, gfp_t flags);
+
+/**
  * genlmsg_unicast - unicast a netlink message
  * @skb: netlink message as socket buffer
  * @pid: netlink pid of the destination socket
  */
-static inline int genlmsg_unicast(struct sk_buff *skb, u32 pid)
+static inline int genlmsg_unicast(struct net *net, struct sk_buff *skb, u32 pid)
 {
-       return nlmsg_unicast(genl_sock, skb, pid);
+       return nlmsg_unicast(net->genl_sock, skb, pid);
 }
 
 /**
@@ -199,7 +251,7 @@ static inline int genlmsg_unicast(struct sk_buff *skb, u32 pid)
  */
 static inline int genlmsg_reply(struct sk_buff *skb, struct genl_info *info)
 {
-       return genlmsg_unicast(skb, info->snd_pid);
+       return genlmsg_unicast(genl_info_net(info), skb, info->snd_pid);
 }
 
 /**
index f27fd83..ad9a511 100644 (file)
@@ -441,6 +441,18 @@ static inline int ipv6_addr_diff(const struct in6_addr *a1, const struct in6_add
        return __ipv6_addr_diff(a1, a2, sizeof(struct in6_addr));
 }
 
+static __inline__ void ipv6_select_ident(struct frag_hdr *fhdr)
+{
+       static u32 ipv6_fragmentation_id = 1;
+       static DEFINE_SPINLOCK(ip6_id_lock);
+
+       spin_lock_bh(&ip6_id_lock);
+       fhdr->identification = htonl(ipv6_fragmentation_id);
+       if (++ipv6_fragmentation_id == 0)
+               ipv6_fragmentation_id = 1;
+       spin_unlock_bh(&ip6_id_lock);
+}
+
 /*
  *     Prototypes exported by ipv6
  */
index 51b9a37..2b3fbbb 100644 (file)
@@ -443,7 +443,7 @@ extern int dev_get_wireless_info(char * buffer, char **start, off_t offset,
 extern void wireless_send_event(struct net_device *    dev,
                                unsigned int            cmd,
                                union iwreq_data *      wrqu,
-                               char *                  extra);
+                               const char *            extra);
 
 /* We may need a function to send a stream of events to user space.
  * More on that later... */
index c061044..ce7cb1b 100644 (file)
@@ -397,6 +397,11 @@ static inline struct ieee80211_tx_info *IEEE80211_SKB_CB(struct sk_buff *skb)
        return (struct ieee80211_tx_info *)skb->cb;
 }
 
+static inline struct ieee80211_rx_status *IEEE80211_SKB_RXCB(struct sk_buff *skb)
+{
+       return (struct ieee80211_rx_status *)skb->cb;
+}
+
 /**
  * ieee80211_tx_info_clear_status - clear TX status
  *
@@ -478,7 +483,7 @@ enum mac80211_rx_flags {
  *
  * The low-level driver should provide this information (the subset
  * supported by hardware) to the 802.11 code with each received
- * frame.
+ * frame, in the skb's control buffer (cb).
  *
  * @mactime: value in microseconds of the 64-bit Time Synchronization Function
  *     (TSF) timer when the first data symbol (MPDU) arrived at the hardware.
@@ -1411,6 +1416,8 @@ enum ieee80211_ampdu_mlme_action {
  * @rfkill_poll: Poll rfkill hardware state. If you need this, you also
  *     need to set wiphy->rfkill_poll to %true before registration,
  *     and need to call wiphy_rfkill_set_hw_state() in the callback.
+ *
+ * @testmode_cmd: Implement a cfg80211 test mode command.
  */
 struct ieee80211_ops {
        int (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb);
@@ -1461,6 +1468,9 @@ struct ieee80211_ops {
                            struct ieee80211_sta *sta, u16 tid, u16 *ssn);
 
        void (*rfkill_poll)(struct ieee80211_hw *hw);
+#ifdef CONFIG_NL80211_TESTMODE
+       int (*testmode_cmd)(struct ieee80211_hw *hw, void *data, int len);
+#endif
 };
 
 /**
@@ -1606,9 +1616,11 @@ void ieee80211_free_hw(struct ieee80211_hw *hw);
  */
 void ieee80211_restart_hw(struct ieee80211_hw *hw);
 
-/* trick to avoid symbol clashes with the ieee80211 subsystem */
-void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb,
-                   struct ieee80211_rx_status *status);
+/*
+ * trick to avoid symbol clashes with the ieee80211 subsystem,
+ * use the inline below instead
+ */
+void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb);
 
 /**
  * ieee80211_rx - receive frame
@@ -1624,13 +1636,10 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb,
  *
  * @hw: the hardware this frame came in on
  * @skb: the buffer to receive, owned by mac80211 after this call
- * @status: status of this frame; the status pointer need not be valid
- *     after this function returns
  */
-static inline void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb,
-                               struct ieee80211_rx_status *status)
+static inline void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb)
 {
-       __ieee80211_rx(hw, skb, status);
+       __ieee80211_rx(hw, skb);
 }
 
 /**
@@ -1644,13 +1653,8 @@ static inline void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb,
  *
  * @hw: the hardware this frame came in on
  * @skb: the buffer to receive, owned by mac80211 after this call
- * @status: status of this frame; the status pointer need not be valid
- *     after this function returns and is not freed by mac80211,
- *     it is recommended that it points to a stack area
  */
-void ieee80211_rx_irqsafe(struct ieee80211_hw *hw,
-                         struct sk_buff *skb,
-                         struct ieee80211_rx_status *status);
+void ieee80211_rx_irqsafe(struct ieee80211_hw *hw, struct sk_buff *skb);
 
 /**
  * ieee80211_tx_status - transmit status callback
index ded434b..a120284 100644 (file)
@@ -26,6 +26,7 @@ struct net_device;
 struct sock;
 struct ctl_table_header;
 struct net_generic;
+struct sock;
 
 struct net {
        atomic_t                count;          /* To decided when the network
@@ -57,6 +58,7 @@ struct net {
        spinlock_t              rules_mod_lock;
 
        struct sock             *rtnl;                  /* rtnetlink socket */
+       struct sock             *genl_sock;
 
        struct netns_core       core;
        struct netns_mib        mib;
@@ -78,6 +80,9 @@ struct net {
 #ifdef CONFIG_XFRM
        struct netns_xfrm       xfrm;
 #endif
+#ifdef CONFIG_WIRELESS_EXT
+       struct sk_buff_head     wext_nlevents;
+#endif
        struct net_generic      *gen;
 };
 
@@ -106,6 +111,8 @@ static inline struct net *copy_net_ns(unsigned long flags, struct net *net_ns)
 
 extern struct list_head net_namespace_list;
 
+extern struct net *get_net_ns_by_pid(pid_t pid);
+
 #ifdef CONFIG_NET_NS
 extern void __put_net(struct net *net);
 
@@ -208,6 +215,9 @@ static inline struct net *read_pnet(struct net * const *pnet)
 #define for_each_net(VAR)                              \
        list_for_each_entry(VAR, &net_namespace_list, list)
 
+#define for_each_net_rcu(VAR)                          \
+       list_for_each_entry_rcu(VAR, &net_namespace_list, list)
+
 #ifdef CONFIG_NET_NS
 #define __net_init
 #define __net_exit
@@ -229,13 +239,15 @@ struct pernet_operations {
  * 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.
+ * Network interfaces need to be removed from a dying netns _before_
+ * subsys notifiers can be called, as most of the network code cleanup
+ * (which is done from subsys notifiers) 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
index 9554a64..591db7d 100644 (file)
@@ -8,8 +8,11 @@ struct ebt_table;
 
 struct netns_xt {
        struct list_head tables[NFPROTO_NUMPROTO];
+#if defined(CONFIG_BRIDGE_NF_EBTABLES) || \
+    defined(CONFIG_BRIDGE_NF_EBTABLES_MODULE)
        struct ebt_table *broute_table;
        struct ebt_table *frame_filter;
        struct ebt_table *frame_nat;
+#endif
 };
 #endif
index 29d1267..44c923c 100644 (file)
@@ -49,4 +49,6 @@ void phonet_address_notify(int event, struct net_device *dev, u8 addr);
 
 #define PN_NO_ADDR     0xff
 
+extern const struct file_operations pn_sock_seq_fops;
+
 #endif
index f45bb6e..cf48c80 100644 (file)
@@ -26,7 +26,6 @@ struct scm_cookie
 #ifdef CONFIG_SECURITY_NETWORK
        u32                     secid;          /* Passed security ID   */
 #endif
-       unsigned long           seq;            /* Connection seqno     */
 };
 
 extern void scm_detach_fds(struct msghdr *msg, struct scm_cookie *scm);
@@ -59,7 +58,6 @@ static __inline__ int scm_send(struct socket *sock, struct msghdr *msg,
        scm->creds.gid = current_gid();
        scm->creds.pid = task_tgid_vnr(p);
        scm->fp = NULL;
-       scm->seq = 0;
        unix_get_peersec_dgram(sock, scm);
        if (msg->msg_controllen <= 0)
                return 0;
index 90e6ce5..5fb029f 100644 (file)
@@ -207,4 +207,7 @@ extern void udp4_proc_exit(void);
 #endif
 
 extern void udp_init(void);
+
+extern int udp4_ufo_send_check(struct sk_buff *skb);
+extern struct sk_buff *udp4_ufo_fragment(struct sk_buff *skb, int features);
 #endif /* _UDP_H */
index e35ba2c..c5e68ad 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/nsproxy.h>
 #include <linux/pid.h>
 #include <linux/ipc_namespace.h>
+#include <linux/ima.h>
 
 #include <net/sock.h>
 #include "util.h"
@@ -733,6 +734,7 @@ SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, mode_t, mode,
                error = PTR_ERR(filp);
                goto out_putfd;
        }
+       ima_counts_get(filp);
 
        fd_install(fd, filp);
        goto out_upsem;
index 780c8dc..2093a69 100644 (file)
@@ -96,6 +96,7 @@ obj-$(CONFIG_HAVE_GENERIC_DMA_COHERENT) += dma-coherent.o
 obj-$(CONFIG_FUNCTION_TRACER) += trace/
 obj-$(CONFIG_TRACING) += trace/
 obj-$(CONFIG_X86_DS) += trace/
+obj-$(CONFIG_RING_BUFFER) += trace/
 obj-$(CONFIG_SMP) += sched_cpupri.o
 obj-$(CONFIG_SLOW_WORK) += slow-work.o
 obj-$(CONFIG_PERF_COUNTERS) += perf_counter.o
index 7afa315..9f33910 100644 (file)
@@ -215,6 +215,7 @@ static void acct_file_reopen(struct bsd_acct_struct *acct, struct file *file,
 static int acct_on(char *name)
 {
        struct file *file;
+       struct vfsmount *mnt;
        int error;
        struct pid_namespace *ns;
        struct bsd_acct_struct *acct = NULL;
@@ -256,11 +257,12 @@ static int acct_on(char *name)
                acct = NULL;
        }
 
-       mnt_pin(file->f_path.mnt);
+       mnt = file->f_path.mnt;
+       mnt_pin(mnt);
        acct_file_reopen(ns->bacct, file, ns);
        spin_unlock(&acct_lock);
 
-       mntput(file->f_path.mnt); /* it's pinned, now give up active reference */
+       mntput(mnt); /* it's pinned, now give up active reference */
        kfree(acct);
 
        return 0;
index 1c33711..794c862 100644 (file)
@@ -299,7 +299,7 @@ void put_futex_key(int fshared, union futex_key *key)
 static int fault_in_user_writeable(u32 __user *uaddr)
 {
        int ret = get_user_pages(current, current->mm, (unsigned long)uaddr,
-                                sizeof(*uaddr), 1, 0, NULL, NULL);
+                                1, 1, 0, NULL, NULL);
        return ret < 0 ? ret : 0;
 }
 
index 1a933a2..d55a50d 100644 (file)
@@ -236,6 +236,8 @@ list_add_counter(struct perf_counter *counter, struct perf_counter_context *ctx)
 
        list_add_rcu(&counter->event_entry, &ctx->event_list);
        ctx->nr_counters++;
+       if (counter->attr.inherit_stat)
+               ctx->nr_stat++;
 }
 
 /*
@@ -250,6 +252,8 @@ list_del_counter(struct perf_counter *counter, struct perf_counter_context *ctx)
        if (list_empty(&counter->list_entry))
                return;
        ctx->nr_counters--;
+       if (counter->attr.inherit_stat)
+               ctx->nr_stat--;
 
        list_del_init(&counter->list_entry);
        list_del_rcu(&counter->event_entry);
@@ -1006,6 +1010,81 @@ static int context_equiv(struct perf_counter_context *ctx1,
                && !ctx1->pin_count && !ctx2->pin_count;
 }
 
+static void __perf_counter_read(void *counter);
+
+static void __perf_counter_sync_stat(struct perf_counter *counter,
+                                    struct perf_counter *next_counter)
+{
+       u64 value;
+
+       if (!counter->attr.inherit_stat)
+               return;
+
+       /*
+        * Update the counter value, we cannot use perf_counter_read()
+        * because we're in the middle of a context switch and have IRQs
+        * disabled, which upsets smp_call_function_single(), however
+        * we know the counter must be on the current CPU, therefore we
+        * don't need to use it.
+        */
+       switch (counter->state) {
+       case PERF_COUNTER_STATE_ACTIVE:
+               __perf_counter_read(counter);
+               break;
+
+       case PERF_COUNTER_STATE_INACTIVE:
+               update_counter_times(counter);
+               break;
+
+       default:
+               break;
+       }
+
+       /*
+        * In order to keep per-task stats reliable we need to flip the counter
+        * values when we flip the contexts.
+        */
+       value = atomic64_read(&next_counter->count);
+       value = atomic64_xchg(&counter->count, value);
+       atomic64_set(&next_counter->count, value);
+
+       swap(counter->total_time_enabled, next_counter->total_time_enabled);
+       swap(counter->total_time_running, next_counter->total_time_running);
+
+       /*
+        * Since we swizzled the values, update the user visible data too.
+        */
+       perf_counter_update_userpage(counter);
+       perf_counter_update_userpage(next_counter);
+}
+
+#define list_next_entry(pos, member) \
+       list_entry(pos->member.next, typeof(*pos), member)
+
+static void perf_counter_sync_stat(struct perf_counter_context *ctx,
+                                  struct perf_counter_context *next_ctx)
+{
+       struct perf_counter *counter, *next_counter;
+
+       if (!ctx->nr_stat)
+               return;
+
+       counter = list_first_entry(&ctx->event_list,
+                                  struct perf_counter, event_entry);
+
+       next_counter = list_first_entry(&next_ctx->event_list,
+                                       struct perf_counter, event_entry);
+
+       while (&counter->event_entry != &ctx->event_list &&
+              &next_counter->event_entry != &next_ctx->event_list) {
+
+               __perf_counter_sync_stat(counter, next_counter);
+
+               counter = list_next_entry(counter, event_entry);
+               next_counter = list_next_entry(counter, event_entry);
+       }
+}
+
 /*
  * Called from scheduler to remove the counters of the current task,
  * with interrupts disabled.
@@ -1061,6 +1140,8 @@ void perf_counter_task_sched_out(struct task_struct *task,
                        ctx->task = next;
                        next_ctx->task = task;
                        do_switch = 0;
+
+                       perf_counter_sync_stat(ctx, next_ctx);
                }
                spin_unlock(&next_ctx->lock);
                spin_unlock(&ctx->lock);
@@ -1348,9 +1429,56 @@ void perf_counter_task_tick(struct task_struct *curr, int cpu)
 }
 
 /*
+ * Enable all of a task's counters that have been marked enable-on-exec.
+ * This expects task == current.
+ */
+static void perf_counter_enable_on_exec(struct task_struct *task)
+{
+       struct perf_counter_context *ctx;
+       struct perf_counter *counter;
+       unsigned long flags;
+       int enabled = 0;
+
+       local_irq_save(flags);
+       ctx = task->perf_counter_ctxp;
+       if (!ctx || !ctx->nr_counters)
+               goto out;
+
+       __perf_counter_task_sched_out(ctx);
+
+       spin_lock(&ctx->lock);
+
+       list_for_each_entry(counter, &ctx->counter_list, list_entry) {
+               if (!counter->attr.enable_on_exec)
+                       continue;
+               counter->attr.enable_on_exec = 0;
+               if (counter->state >= PERF_COUNTER_STATE_INACTIVE)
+                       continue;
+               counter->state = PERF_COUNTER_STATE_INACTIVE;
+               counter->tstamp_enabled =
+                       ctx->time - counter->total_time_enabled;
+               enabled = 1;
+       }
+
+       /*
+        * Unclone this context if we enabled any counter.
+        */
+       if (enabled && ctx->parent_ctx) {
+               put_ctx(ctx->parent_ctx);
+               ctx->parent_ctx = NULL;
+       }
+
+       spin_unlock(&ctx->lock);
+
+       perf_counter_task_sched_in(task, smp_processor_id());
+ out:
+       local_irq_restore(flags);
+}
+
+/*
  * Cross CPU call to read the hardware counter
  */
-static void __read(void *info)
+static void __perf_counter_read(void *info)
 {
        struct perf_counter *counter = info;
        struct perf_counter_context *ctx = counter->ctx;
@@ -1372,7 +1500,7 @@ static u64 perf_counter_read(struct perf_counter *counter)
         */
        if (counter->state == PERF_COUNTER_STATE_ACTIVE) {
                smp_call_function_single(counter->oncpu,
-                                        __read, counter, 1);
+                                        __perf_counter_read, counter, 1);
        } else if (counter->state == PERF_COUNTER_STATE_INACTIVE) {
                update_counter_times(counter);
        }
@@ -1508,11 +1636,13 @@ static void free_counter(struct perf_counter *counter)
 {
        perf_pending_sync(counter);
 
-       atomic_dec(&nr_counters);
-       if (counter->attr.mmap)
-               atomic_dec(&nr_mmap_counters);
-       if (counter->attr.comm)
-               atomic_dec(&nr_comm_counters);
+       if (!counter->parent) {
+               atomic_dec(&nr_counters);
+               if (counter->attr.mmap)
+                       atomic_dec(&nr_mmap_counters);
+               if (counter->attr.comm)
+                       atomic_dec(&nr_comm_counters);
+       }
 
        if (counter->destroy)
                counter->destroy(counter);
@@ -1751,6 +1881,14 @@ int perf_counter_task_disable(void)
        return 0;
 }
 
+static int perf_counter_index(struct perf_counter *counter)
+{
+       if (counter->state != PERF_COUNTER_STATE_ACTIVE)
+               return 0;
+
+       return counter->hw.idx + 1 - PERF_COUNTER_INDEX_OFFSET;
+}
+
 /*
  * Callers need to ensure there can be no nesting of this function, otherwise
  * the seqlock logic goes bad. We can not serialize this because the arch
@@ -1775,11 +1913,17 @@ void perf_counter_update_userpage(struct perf_counter *counter)
        preempt_disable();
        ++userpg->lock;
        barrier();
-       userpg->index = counter->hw.idx;
+       userpg->index = perf_counter_index(counter);
        userpg->offset = atomic64_read(&counter->count);
        if (counter->state == PERF_COUNTER_STATE_ACTIVE)
                userpg->offset -= atomic64_read(&counter->hw.prev_count);
 
+       userpg->time_enabled = counter->total_time_enabled +
+                       atomic64_read(&counter->child_total_time_enabled);
+
+       userpg->time_running = counter->total_time_running +
+                       atomic64_read(&counter->child_total_time_running);
+
        barrier();
        ++userpg->lock;
        preempt_enable();
@@ -2483,15 +2627,14 @@ static void perf_counter_output(struct perf_counter *counter, int nmi,
                u32 cpu, reserved;
        } cpu_entry;
 
-       header.type = 0;
+       header.type = PERF_EVENT_SAMPLE;
        header.size = sizeof(header);
 
-       header.misc = PERF_EVENT_MISC_OVERFLOW;
+       header.misc = 0;
        header.misc |= perf_misc_flags(data->regs);
 
        if (sample_type & PERF_SAMPLE_IP) {
                ip = perf_instruction_pointer(data->regs);
-               header.type |= PERF_SAMPLE_IP;
                header.size += sizeof(ip);
        }
 
@@ -2500,7 +2643,6 @@ static void perf_counter_output(struct perf_counter *counter, int nmi,
                tid_entry.pid = perf_counter_pid(counter, current);
                tid_entry.tid = perf_counter_tid(counter, current);
 
-               header.type |= PERF_SAMPLE_TID;
                header.size += sizeof(tid_entry);
        }
 
@@ -2510,34 +2652,25 @@ static void perf_counter_output(struct perf_counter *counter, int nmi,
                 */
                time = sched_clock();
 
-               header.type |= PERF_SAMPLE_TIME;
                header.size += sizeof(u64);
        }
 
-       if (sample_type & PERF_SAMPLE_ADDR) {
-               header.type |= PERF_SAMPLE_ADDR;
+       if (sample_type & PERF_SAMPLE_ADDR)
                header.size += sizeof(u64);
-       }
 
-       if (sample_type & PERF_SAMPLE_ID) {
-               header.type |= PERF_SAMPLE_ID;
+       if (sample_type & PERF_SAMPLE_ID)
                header.size += sizeof(u64);
-       }
 
        if (sample_type & PERF_SAMPLE_CPU) {
-               header.type |= PERF_SAMPLE_CPU;
                header.size += sizeof(cpu_entry);
 
                cpu_entry.cpu = raw_smp_processor_id();
        }
 
-       if (sample_type & PERF_SAMPLE_PERIOD) {
-               header.type |= PERF_SAMPLE_PERIOD;
+       if (sample_type & PERF_SAMPLE_PERIOD)
                header.size += sizeof(u64);
-       }
 
        if (sample_type & PERF_SAMPLE_GROUP) {
-               header.type |= PERF_SAMPLE_GROUP;
                header.size += sizeof(u64) +
                        counter->nr_siblings * sizeof(group_entry);
        }
@@ -2547,10 +2680,9 @@ static void perf_counter_output(struct perf_counter *counter, int nmi,
 
                if (callchain) {
                        callchain_size = (1 + callchain->nr) * sizeof(u64);
-
-                       header.type |= PERF_SAMPLE_CALLCHAIN;
                        header.size += callchain_size;
-               }
+               } else
+                       header.size += sizeof(u64);
        }
 
        ret = perf_output_begin(&handle, counter, header.size, nmi, 1);
@@ -2601,13 +2733,79 @@ static void perf_counter_output(struct perf_counter *counter, int nmi,
                }
        }
 
-       if (callchain)
-               perf_output_copy(&handle, callchain, callchain_size);
+       if (sample_type & PERF_SAMPLE_CALLCHAIN) {
+               if (callchain)
+                       perf_output_copy(&handle, callchain, callchain_size);
+               else {
+                       u64 nr = 0;
+                       perf_output_put(&handle, nr);
+               }
+       }
 
        perf_output_end(&handle);
 }
 
 /*
+ * read event
+ */
+
+struct perf_read_event {
+       struct perf_event_header        header;
+
+       u32                             pid;
+       u32                             tid;
+       u64                             value;
+       u64                             format[3];
+};
+
+static void
+perf_counter_read_event(struct perf_counter *counter,
+                       struct task_struct *task)
+{
+       struct perf_output_handle handle;
+       struct perf_read_event event = {
+               .header = {
+                       .type = PERF_EVENT_READ,
+                       .misc = 0,
+                       .size = sizeof(event) - sizeof(event.format),
+               },
+               .pid = perf_counter_pid(counter, task),
+               .tid = perf_counter_tid(counter, task),
+               .value = atomic64_read(&counter->count),
+       };
+       int ret, i = 0;
+
+       if (counter->attr.read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) {
+               event.header.size += sizeof(u64);
+               event.format[i++] = counter->total_time_enabled;
+       }
+
+       if (counter->attr.read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) {
+               event.header.size += sizeof(u64);
+               event.format[i++] = counter->total_time_running;
+       }
+
+       if (counter->attr.read_format & PERF_FORMAT_ID) {
+               u64 id;
+
+               event.header.size += sizeof(u64);
+               if (counter->parent)
+                       id = counter->parent->id;
+               else
+                       id = counter->id;
+
+               event.format[i++] = id;
+       }
+
+       ret = perf_output_begin(&handle, counter, event.header.size, 0, 0);
+       if (ret)
+               return;
+
+       perf_output_copy(&handle, &event, event.header.size);
+       perf_output_end(&handle);
+}
+
+/*
  * fork tracking
  */
 
@@ -2798,6 +2996,9 @@ void perf_counter_comm(struct task_struct *task)
 {
        struct perf_comm_event comm_event;
 
+       if (task->perf_counter_ctxp)
+               perf_counter_enable_on_exec(task);
+
        if (!atomic_read(&nr_comm_counters))
                return;
 
@@ -3317,8 +3518,8 @@ out:
        put_cpu_var(perf_cpu_context);
 }
 
-void
-perf_swcounter_event(u32 event, u64 nr, int nmi, struct pt_regs *regs, u64 addr)
+void __perf_swcounter_event(u32 event, u64 nr, int nmi,
+                           struct pt_regs *regs, u64 addr)
 {
        struct perf_sample_data data = {
                .regs = regs,
@@ -3509,9 +3710,21 @@ static const struct pmu *tp_perf_counter_init(struct perf_counter *counter)
 }
 #endif
 
+atomic_t perf_swcounter_enabled[PERF_COUNT_SW_MAX];
+
+static void sw_perf_counter_destroy(struct perf_counter *counter)
+{
+       u64 event = counter->attr.config;
+
+       WARN_ON(counter->parent);
+
+       atomic_dec(&perf_swcounter_enabled[event]);
+}
+
 static const struct pmu *sw_perf_counter_init(struct perf_counter *counter)
 {
        const struct pmu *pmu = NULL;
+       u64 event = counter->attr.config;
 
        /*
         * Software counters (currently) can't in general distinguish
@@ -3520,7 +3733,7 @@ static const struct pmu *sw_perf_counter_init(struct perf_counter *counter)
         * to be kernel events, and page faults are never hypervisor
         * events.
         */
-       switch (counter->attr.config) {
+       switch (event) {
        case PERF_COUNT_SW_CPU_CLOCK:
                pmu = &perf_ops_cpu_clock;
 
@@ -3541,6 +3754,10 @@ static const struct pmu *sw_perf_counter_init(struct perf_counter *counter)
        case PERF_COUNT_SW_PAGE_FAULTS_MAJ:
        case PERF_COUNT_SW_CONTEXT_SWITCHES:
        case PERF_COUNT_SW_CPU_MIGRATIONS:
+               if (!counter->parent) {
+                       atomic_inc(&perf_swcounter_enabled[event]);
+                       counter->destroy = sw_perf_counter_destroy;
+               }
                pmu = &perf_ops_generic;
                break;
        }
@@ -3556,6 +3773,7 @@ perf_counter_alloc(struct perf_counter_attr *attr,
                   int cpu,
                   struct perf_counter_context *ctx,
                   struct perf_counter *group_leader,
+                  struct perf_counter *parent_counter,
                   gfp_t gfpflags)
 {
        const struct pmu *pmu;
@@ -3591,6 +3809,8 @@ perf_counter_alloc(struct perf_counter_attr *attr,
        counter->ctx            = ctx;
        counter->oncpu          = -1;
 
+       counter->parent         = parent_counter;
+
        counter->ns             = get_pid_ns(current->nsproxy->pid_ns);
        counter->id             = atomic64_inc_return(&perf_counter_id);
 
@@ -3648,11 +3868,13 @@ done:
 
        counter->pmu = pmu;
 
-       atomic_inc(&nr_counters);
-       if (counter->attr.mmap)
-               atomic_inc(&nr_mmap_counters);
-       if (counter->attr.comm)
-               atomic_inc(&nr_comm_counters);
+       if (!counter->parent) {
+               atomic_inc(&nr_counters);
+               if (counter->attr.mmap)
+                       atomic_inc(&nr_mmap_counters);
+               if (counter->attr.comm)
+                       atomic_inc(&nr_comm_counters);
+       }
 
        return counter;
 }
@@ -3815,7 +4037,7 @@ SYSCALL_DEFINE5(perf_counter_open,
        }
 
        counter = perf_counter_alloc(&attr, cpu, ctx, group_leader,
-                                    GFP_KERNEL);
+                                    NULL, GFP_KERNEL);
        ret = PTR_ERR(counter);
        if (IS_ERR(counter))
                goto err_put_context;
@@ -3881,7 +4103,8 @@ inherit_counter(struct perf_counter *parent_counter,
 
        child_counter = perf_counter_alloc(&parent_counter->attr,
                                           parent_counter->cpu, child_ctx,
-                                          group_leader, GFP_KERNEL);
+                                          group_leader, parent_counter,
+                                          GFP_KERNEL);
        if (IS_ERR(child_counter))
                return child_counter;
        get_ctx(child_ctx);
@@ -3904,12 +4127,6 @@ inherit_counter(struct perf_counter *parent_counter,
         */
        add_counter_to_ctx(child_counter, child_ctx);
 
-       child_counter->parent = parent_counter;
-       /*
-        * inherit into child's child as well:
-        */
-       child_counter->attr.inherit = 1;
-
        /*
         * Get a reference to the parent filp - we will fput it
         * when the child counter exits. This is safe to do because
@@ -3953,10 +4170,14 @@ static int inherit_group(struct perf_counter *parent_counter,
 }
 
 static void sync_child_counter(struct perf_counter *child_counter,
-                              struct perf_counter *parent_counter)
+                              struct task_struct *child)
 {
+       struct perf_counter *parent_counter = child_counter->parent;
        u64 child_val;
 
+       if (child_counter->attr.inherit_stat)
+               perf_counter_read_event(child_counter, child);
+
        child_val = atomic64_read(&child_counter->count);
 
        /*
@@ -3985,7 +4206,8 @@ static void sync_child_counter(struct perf_counter *child_counter,
 
 static void
 __perf_counter_exit_task(struct perf_counter *child_counter,
-                        struct perf_counter_context *child_ctx)
+                        struct perf_counter_context *child_ctx,
+                        struct task_struct *child)
 {
        struct perf_counter *parent_counter;
 
@@ -3999,7 +4221,7 @@ __perf_counter_exit_task(struct perf_counter *child_counter,
         * counters need to be zapped - but otherwise linger.
         */
        if (parent_counter) {
-               sync_child_counter(child_counter, parent_counter);
+               sync_child_counter(child_counter, child);
                free_counter(child_counter);
        }
 }
@@ -4061,7 +4283,7 @@ void perf_counter_exit_task(struct task_struct *child)
 again:
        list_for_each_entry_safe(child_counter, tmp, &child_ctx->counter_list,
                                 list_entry)
-               __perf_counter_exit_task(child_counter, child_ctx);
+               __perf_counter_exit_task(child_counter, child_ctx, child);
 
        /*
         * If the last counter was a group counter, it will have appended all
index 31310b5..5fa1db4 100644 (file)
@@ -36,6 +36,7 @@
 #include <linux/pid_namespace.h>
 #include <linux/init_task.h>
 #include <linux/syscalls.h>
+#include <linux/kmemleak.h>
 
 #define pid_hashfn(nr, ns)     \
        hash_long((unsigned long)nr + (unsigned long)ns, pidhash_shift)
@@ -512,6 +513,12 @@ void __init pidhash_init(void)
        pid_hash = alloc_bootmem(pidhash_size * sizeof(*(pid_hash)));
        if (!pid_hash)
                panic("Could not alloc pidhash!\n");
+       /*
+        * pid_hash contains references to allocated struct pid objects and it
+        * must be scanned by kmemleak to avoid false positives.
+        */
+       kmemleak_alloc(pid_hash, pidhash_size * sizeof(*(pid_hash)), 0,
+                      GFP_KERNEL);
        for (i = 0; i < pidhash_size; i++)
                INIT_HLIST_HEAD(&pid_hash[i]);
 }
index ac5f3a3..78b0872 100644 (file)
@@ -787,7 +787,7 @@ static int __init reserve_setup(char *str)
        static struct resource reserve[MAXRESERVE];
 
        for (;;) {
-               int io_start, io_num;
+               unsigned int io_start, io_num;
                int x = reserved;
 
                if (get_option (&str, &io_start) != 2)
index 62e4ff9..98e0232 100644 (file)
@@ -335,7 +335,10 @@ static struct ctl_table kern_table[] = {
                .data           = &sysctl_timer_migration,
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec,
+               .proc_handler   = &proc_dointvec_minmax,
+               .strategy       = &sysctl_intvec,
+               .extra1         = &zero,
+               .extra2         = &one,
        },
 #endif
        {
@@ -744,6 +747,14 @@ static struct ctl_table kern_table[] = {
                .proc_handler   = &proc_dointvec,
        },
        {
+               .ctl_name       = CTL_UNNUMBERED,
+               .procname       = "panic_on_io_nmi",
+               .data           = &panic_on_io_nmi,
+               .maxlen         = sizeof(int),
+               .mode           = 0644,
+               .proc_handler   = &proc_dointvec,
+       },
+       {
                .ctl_name       = KERN_BOOTLOADER_TYPE,
                .procname       = "bootloader_type",
                .data           = &bootloader_type,
index 888adbc..ea8384d 100644 (file)
@@ -108,7 +108,7 @@ static int prepare_reply(struct genl_info *info, u8 cmd, struct sk_buff **skbp,
 /*
  * Send taskstats data in @skb to listener with nl_pid @pid
  */
-static int send_reply(struct sk_buff *skb, pid_t pid)
+static int send_reply(struct sk_buff *skb, struct genl_info *info)
 {
        struct genlmsghdr *genlhdr = nlmsg_data(nlmsg_hdr(skb));
        void *reply = genlmsg_data(genlhdr);
@@ -120,7 +120,7 @@ static int send_reply(struct sk_buff *skb, pid_t pid)
                return rc;
        }
 
-       return genlmsg_unicast(skb, pid);
+       return genlmsg_reply(skb, info);
 }
 
 /*
@@ -150,7 +150,7 @@ static void send_cpu_listeners(struct sk_buff *skb,
                        if (!skb_next)
                                break;
                }
-               rc = genlmsg_unicast(skb_cur, s->pid);
+               rc = genlmsg_unicast(&init_net, skb_cur, s->pid);
                if (rc == -ECONNREFUSED) {
                        s->valid = 0;
                        delcount++;
@@ -418,7 +418,7 @@ static int cgroupstats_user_cmd(struct sk_buff *skb, struct genl_info *info)
                goto err;
        }
 
-       rc = send_reply(rep_skb, info->snd_pid);
+       rc = send_reply(rep_skb, info);
 
 err:
        fput_light(file, fput_needed);
@@ -487,7 +487,7 @@ free_return_rc:
        } else
                goto err;
 
-       return send_reply(rep_skb, info->snd_pid);
+       return send_reply(rep_skb, info);
 err:
        nlmsg_free(rep_skb);
        return rc;
index c994530..4cde8b9 100644 (file)
@@ -96,7 +96,7 @@ static DEFINE_MUTEX(show_mutex);
 /*
  * Collection status, active/inactive:
  */
-static int __read_mostly active;
+int __read_mostly timer_stats_active;
 
 /*
  * Beginning/end timestamps of measurement:
@@ -242,7 +242,7 @@ void timer_stats_update_stats(void *timer, pid_t pid, void *startf,
        struct entry *entry, input;
        unsigned long flags;
 
-       if (likely(!active))
+       if (likely(!timer_stats_active))
                return;
 
        lock = &per_cpu(lookup_lock, raw_smp_processor_id());
@@ -254,7 +254,7 @@ void timer_stats_update_stats(void *timer, pid_t pid, void *startf,
        input.timer_flag = timer_flag;
 
        spin_lock_irqsave(lock, flags);
-       if (!active)
+       if (!timer_stats_active)
                goto out_unlock;
 
        entry = tstat_lookup(&input, comm);
@@ -290,7 +290,7 @@ static int tstats_show(struct seq_file *m, void *v)
        /*
         * If still active then calculate up to now:
         */
-       if (active)
+       if (timer_stats_active)
                time_stop = ktime_get();
 
        time = ktime_sub(time_stop, time_start);
@@ -368,18 +368,18 @@ static ssize_t tstats_write(struct file *file, const char __user *buf,
        mutex_lock(&show_mutex);
        switch (ctl[0]) {
        case '0':
-               if (active) {
-                       active = 0;
+               if (timer_stats_active) {
+                       timer_stats_active = 0;
                        time_stop = ktime_get();
                        sync_access();
                }
                break;
        case '1':
-               if (!active) {
+               if (!timer_stats_active) {
                        reset_entries();
                        time_start = ktime_get();
                        smp_mb();
-                       active = 1;
+                       timer_stats_active = 1;
                }
                break;
        default:
index 54d3912..0b36b9e 100644 (file)
@@ -380,6 +380,8 @@ static void timer_stats_account_timer(struct timer_list *timer)
 {
        unsigned int flag = 0;
 
+       if (likely(!timer->start_site))
+               return;
        if (unlikely(tbase_get_deferrable(timer->base)))
                flag |= TIMER_STATS_FLAG_DEFERRABLE;
 
index 3718d55..f3716bf 100644 (file)
@@ -291,7 +291,9 @@ function_stat_next(void *v, int idx)
        pg = (struct ftrace_profile_page *)((unsigned long)rec & PAGE_MASK);
 
  again:
-       rec++;
+       if (idx != 0)
+               rec++;
+
        if ((void *)rec >= (void *)&pg->records[pg->index]) {
                pg = pg->next;
                if (!pg)
@@ -1417,10 +1419,20 @@ static void *t_hash_start(struct seq_file *m, loff_t *pos)
 {
        struct ftrace_iterator *iter = m->private;
        void *p = NULL;
+       loff_t l;
+
+       if (!(iter->flags & FTRACE_ITER_HASH))
+               *pos = 0;
 
        iter->flags |= FTRACE_ITER_HASH;
 
-       return t_hash_next(m, p, pos);
+       iter->hidx = 0;
+       for (l = 0; l <= *pos; ) {
+               p = t_hash_next(m, p, &l);
+               if (!p)
+                       break;
+       }
+       return p;
 }
 
 static int t_hash_show(struct seq_file *m, void *v)
@@ -1467,8 +1479,6 @@ t_next(struct seq_file *m, void *v, loff_t *pos)
                        iter->pg = iter->pg->next;
                        iter->idx = 0;
                        goto retry;
-               } else {
-                       iter->idx = -1;
                }
        } else {
                rec = &iter->pg->records[iter->idx++];
@@ -1497,6 +1507,7 @@ static void *t_start(struct seq_file *m, loff_t *pos)
 {
        struct ftrace_iterator *iter = m->private;
        void *p = NULL;
+       loff_t l;
 
        mutex_lock(&ftrace_lock);
        /*
@@ -1508,23 +1519,21 @@ static void *t_start(struct seq_file *m, loff_t *pos)
                if (*pos > 0)
                        return t_hash_start(m, pos);
                iter->flags |= FTRACE_ITER_PRINTALL;
-               (*pos)++;
                return iter;
        }
 
        if (iter->flags & FTRACE_ITER_HASH)
                return t_hash_start(m, pos);
 
-       if (*pos > 0) {
-               if (iter->idx < 0)
-                       return p;
-               (*pos)--;
-               iter->idx--;
+       iter->pg = ftrace_pages_start;
+       iter->idx = 0;
+       for (l = 0; l <= *pos; ) {
+               p = t_next(m, p, &l);
+               if (!p)
+                       break;
        }
 
-       p = t_next(m, p, pos);
-
-       if (!p)
+       if (!p && iter->flags & FTRACE_ITER_FILTER)
                return t_hash_start(m, pos);
 
        return p;
@@ -2500,32 +2509,31 @@ int ftrace_graph_count;
 unsigned long ftrace_graph_funcs[FTRACE_GRAPH_MAX_FUNCS] __read_mostly;
 
 static void *
-g_next(struct seq_file *m, void *v, loff_t *pos)
+__g_next(struct seq_file *m, loff_t *pos)
 {
        unsigned long *array = m->private;
-       int index = *pos;
 
-       (*pos)++;
-
-       if (index >= ftrace_graph_count)
+       if (*pos >= ftrace_graph_count)
                return NULL;
+       return &array[*pos];
+}
 
-       return &array[index];
+static void *
+g_next(struct seq_file *m, void *v, loff_t *pos)
+{
+       (*pos)++;
+       return __g_next(m, pos);
 }
 
 static void *g_start(struct seq_file *m, loff_t *pos)
 {
-       void *p = NULL;
-
        mutex_lock(&graph_lock);
 
        /* Nothing, tell g_show to print all functions are enabled */
        if (!ftrace_graph_count && !*pos)
                return (void *)1;
 
-       p = g_next(m, p, pos);
-
-       return p;
+       return __g_next(m, pos);
 }
 
 static void g_stop(struct seq_file *m, void *p)
index 04dac26..bf27bb7 100644 (file)
@@ -1563,6 +1563,8 @@ rb_reserve_next_event(struct ring_buffer_per_cpu *cpu_buffer,
        return NULL;
 }
 
+#ifdef CONFIG_TRACING
+
 #define TRACE_RECURSIVE_DEPTH 16
 
 static int trace_recursive_lock(void)
@@ -1593,6 +1595,13 @@ static void trace_recursive_unlock(void)
        current->trace_recursion--;
 }
 
+#else
+
+#define trace_recursive_lock()         (0)
+#define trace_recursive_unlock()       do { } while (0)
+
+#endif
+
 static DEFINE_PER_CPU(int, rb_need_resched);
 
 /**
@@ -3104,6 +3113,7 @@ int ring_buffer_read_page(struct ring_buffer *buffer,
 }
 EXPORT_SYMBOL_GPL(ring_buffer_read_page);
 
+#ifdef CONFIG_TRACING
 static ssize_t
 rb_simple_read(struct file *filp, char __user *ubuf,
               size_t cnt, loff_t *ppos)
@@ -3171,6 +3181,7 @@ static __init int rb_init_debugfs(void)
 }
 
 fs_initcall(rb_init_debugfs);
+#endif
 
 #ifdef CONFIG_HOTPLUG_CPU
 static int rb_cpu_notify(struct notifier_block *self,
index 076fa6f..3aa0a0d 100644 (file)
@@ -284,13 +284,12 @@ void trace_wake_up(void)
 static int __init set_buf_size(char *str)
 {
        unsigned long buf_size;
-       int ret;
 
        if (!str)
                return 0;
-       ret = strict_strtoul(str, 0, &buf_size);
+       buf_size = memparse(str, &str);
        /* nr_entries can not be zero */
-       if (ret < 0 || buf_size == 0)
+       if (buf_size == 0)
                return 0;
        trace_buf_size = buf_size;
        return 1;
@@ -2053,25 +2052,23 @@ static int tracing_open(struct inode *inode, struct file *file)
 static void *
 t_next(struct seq_file *m, void *v, loff_t *pos)
 {
-       struct tracer *t = m->private;
+       struct tracer *t = v;
 
        (*pos)++;
 
        if (t)
                t = t->next;
 
-       m->private = t;
-
        return t;
 }
 
 static void *t_start(struct seq_file *m, loff_t *pos)
 {
-       struct tracer *t = m->private;
+       struct tracer *t;
        loff_t l = 0;
 
        mutex_lock(&trace_types_lock);
-       for (; t && l < *pos; t = t_next(m, t, &l))
+       for (t = trace_types; t && l < *pos; t = t_next(m, t, &l))
                ;
 
        return t;
@@ -2107,18 +2104,10 @@ static struct seq_operations show_traces_seq_ops = {
 
 static int show_traces_open(struct inode *inode, struct file *file)
 {
-       int ret;
-
        if (tracing_disabled)
                return -ENODEV;
 
-       ret = seq_open(file, &show_traces_seq_ops);
-       if (!ret) {
-               struct seq_file *m = file->private_data;
-               m->private = trace_types;
-       }
-
-       return ret;
+       return seq_open(file, &show_traces_seq_ops);
 }
 
 static ssize_t
index 6e735d4..3548ae5 100644 (file)
@@ -597,6 +597,7 @@ print_graph_function(struct trace_iterator *iter)
 
 extern struct pid *ftrace_pid_trace;
 
+#ifdef CONFIG_FUNCTION_TRACER
 static inline int ftrace_trace_task(struct task_struct *task)
 {
        if (!ftrace_pid_trace)
@@ -604,6 +605,12 @@ static inline int ftrace_trace_task(struct task_struct *task)
 
        return test_tsk_trace_trace(task);
 }
+#else
+static inline int ftrace_trace_task(struct task_struct *task)
+{
+       return 1;
+}
+#endif
 
 /*
  * trace_iterator_flags is an enumeration that defines bit
index aa08be6..53c8fd3 100644 (file)
@@ -300,10 +300,18 @@ t_next(struct seq_file *m, void *v, loff_t *pos)
 
 static void *t_start(struct seq_file *m, loff_t *pos)
 {
+       struct ftrace_event_call *call = NULL;
+       loff_t l;
+
        mutex_lock(&event_mutex);
-       if (*pos == 0)
-               m->private = ftrace_events.next;
-       return t_next(m, NULL, pos);
+
+       m->private = ftrace_events.next;
+       for (l = 0; l <= *pos; ) {
+               call = t_next(m, NULL, &l);
+               if (!call)
+                       break;
+       }
+       return call;
 }
 
 static void *
@@ -332,10 +340,18 @@ s_next(struct seq_file *m, void *v, loff_t *pos)
 
 static void *s_start(struct seq_file *m, loff_t *pos)
 {
+       struct ftrace_event_call *call = NULL;
+       loff_t l;
+
        mutex_lock(&event_mutex);
-       if (*pos == 0)
-               m->private = ftrace_events.next;
-       return s_next(m, NULL, pos);
+
+       m->private = ftrace_events.next;
+       for (l = 0; l <= *pos; ) {
+               call = s_next(m, NULL, &l);
+               if (!call)
+                       break;
+       }
+       return call;
 }
 
 static int t_show(struct seq_file *m, void *v)
index 90f1347..7402144 100644 (file)
@@ -302,8 +302,7 @@ ftrace_trace_onoff_print(struct seq_file *m, unsigned long ip,
        if (count == -1)
                seq_printf(m, ":unlimited\n");
        else
-               seq_printf(m, ":count=%ld", count);
-       seq_putc(m, '\n');
+               seq_printf(m, ":count=%ld\n", count);
 
        return 0;
 }
index 9bece96..7b62781 100644 (file)
@@ -155,25 +155,19 @@ int __ftrace_vprintk(unsigned long ip, const char *fmt, va_list ap)
 EXPORT_SYMBOL_GPL(__ftrace_vprintk);
 
 static void *
-t_next(struct seq_file *m, void *v, loff_t *pos)
+t_start(struct seq_file *m, loff_t *pos)
 {
-       const char **fmt = m->private;
-       const char **next = fmt;
-
-       (*pos)++;
+       const char **fmt = __start___trace_bprintk_fmt + *pos;
 
        if ((unsigned long)fmt >= (unsigned long)__stop___trace_bprintk_fmt)
                return NULL;
-
-       next = fmt;
-       m->private = ++next;
-
        return fmt;
 }
 
-static void *t_start(struct seq_file *m, loff_t *pos)
+static void *t_next(struct seq_file *m, void * v, loff_t *pos)
 {
-       return t_next(m, NULL, pos);
+       (*pos)++;
+       return t_start(m, pos);
 }
 
 static int t_show(struct seq_file *m, void *v)
@@ -224,15 +218,7 @@ static const struct seq_operations show_format_seq_ops = {
 static int
 ftrace_formats_open(struct inode *inode, struct file *file)
 {
-       int ret;
-
-       ret = seq_open(file, &show_format_seq_ops);
-       if (!ret) {
-               struct seq_file *m = file->private_data;
-
-               m->private = __start___trace_bprintk_fmt;
-       }
-       return ret;
+       return seq_open(file, &show_format_seq_ops);
 }
 
 static const struct file_operations ftrace_formats_fops = {
index c006437..e66f5e4 100644 (file)
@@ -199,17 +199,13 @@ static void *stat_seq_start(struct seq_file *s, loff_t *pos)
        mutex_lock(&session->stat_mutex);
 
        /* If we are in the beginning of the file, print the headers */
-       if (!*pos && session->ts->stat_headers) {
-               (*pos)++;
+       if (!*pos && session->ts->stat_headers)
                return SEQ_START_TOKEN;
-       }
 
        node = rb_first(&session->stat_root);
        for (i = 0; node && i < *pos; i++)
                node = rb_next(node);
 
-       (*pos)++;
-
        return node;
 }
 
index 4c32b1a..12327b2 100644 (file)
@@ -359,6 +359,18 @@ config DEBUG_KMEMLEAK
          In order to access the kmemleak file, debugfs needs to be
          mounted (usually at /sys/kernel/debug).
 
+config DEBUG_KMEMLEAK_EARLY_LOG_SIZE
+       int "Maximum kmemleak early log entries"
+       depends on DEBUG_KMEMLEAK
+       range 200 2000
+       default 400
+       help
+         Kmemleak must track all the memory allocations to avoid
+         reporting false positives. Since memory may be allocated or
+         freed before kmemleak is initialised, an early log buffer is
+         used to store these actions. If kmemleak reports "early log
+         buffer exceeded", please increase this value.
+
 config DEBUG_KMEMLEAK_TEST
        tristate "Simple test for the kernel memory leak detector"
        depends on DEBUG_KMEMLEAK
index b1f0885..3df0637 100644 (file)
@@ -86,10 +86,12 @@ show_pools(struct device *dev, struct device_attribute *attr, char *buf)
                unsigned pages = 0;
                unsigned blocks = 0;
 
+               spin_lock_irq(&pool->lock);
                list_for_each_entry(page, &pool->page_list, page_list) {
                        pages++;
                        blocks += page->in_use;
                }
+               spin_unlock_irq(&pool->lock);
 
                /* per-pool info, no real statistics yet */
                temp = scnprintf(next, size, "%-16s %4u %4Zu %4Zu %2u\n",
index c96f2c8..e766e1d 100644 (file)
  *   scanned. This list is only modified during a scanning episode when the
  *   scan_mutex is held. At the end of a scan, the gray_list is always empty.
  *   Note that the kmemleak_object.use_count is incremented when an object is
- *   added to the gray_list and therefore cannot be freed
- * - kmemleak_mutex (mutex): prevents multiple users of the "kmemleak" debugfs
- *   file together with modifications to the memory scanning parameters
- *   including the scan_thread pointer
+ *   added to the gray_list and therefore cannot be freed. This mutex also
+ *   prevents multiple users of the "kmemleak" debugfs file together with
+ *   modifications to the memory scanning parameters including the scan_thread
+ *   pointer
  *
  * The kmemleak_object structures have a use_count incremented or decremented
  * using the get_object()/put_object() functions. When the use_count becomes
 #define MAX_TRACE              16      /* stack trace length */
 #define REPORTS_NR             50      /* maximum number of reported leaks */
 #define MSECS_MIN_AGE          5000    /* minimum object age for reporting */
-#define MSECS_SCAN_YIELD       10      /* CPU yielding period */
 #define SECS_FIRST_SCAN                60      /* delay before the first scan */
 #define SECS_SCAN_WAIT         600     /* subsequent auto scanning delay */
 
@@ -186,19 +185,16 @@ static atomic_t kmemleak_error = ATOMIC_INIT(0);
 static unsigned long min_addr = ULONG_MAX;
 static unsigned long max_addr;
 
-/* used for yielding the CPU to other tasks during scanning */
-static unsigned long next_scan_yield;
 static struct task_struct *scan_thread;
-static unsigned long jiffies_scan_yield;
+/* used to avoid reporting of recently allocated objects */
 static unsigned long jiffies_min_age;
+static unsigned long jiffies_last_scan;
 /* delay between automatic memory scannings */
 static signed long jiffies_scan_wait;
 /* enables or disables the task stacks scanning */
-static int kmemleak_stack_scan;
-/* mutex protecting the memory scanning */
+static int kmemleak_stack_scan = 1;
+/* protects the memory scanning, parameters and debug/kmemleak file access */
 static DEFINE_MUTEX(scan_mutex);
-/* mutex protecting the access to the /sys/kernel/debug/kmemleak file */
-static DEFINE_MUTEX(kmemleak_mutex);
 
 /* number of leaks reported (for limitation purposes) */
 static int reported_leaks;
@@ -235,7 +231,7 @@ struct early_log {
 };
 
 /* early logging buffer and current position */
-static struct early_log early_log[200];
+static struct early_log early_log[CONFIG_DEBUG_KMEMLEAK_EARLY_LOG_SIZE];
 static int crt_early_log;
 
 static void kmemleak_disable(void);
@@ -279,15 +275,6 @@ static int color_gray(const struct kmemleak_object *object)
 }
 
 /*
- * Objects are considered referenced if their color is gray and they have not
- * been deleted.
- */
-static int referenced_object(struct kmemleak_object *object)
-{
-       return (object->flags & OBJECT_ALLOCATED) && color_gray(object);
-}
-
-/*
  * Objects are considered unreferenced only if their color is white, they have
  * not be deleted and have a minimum age to avoid false positives caused by
  * pointers temporarily stored in CPU registers.
@@ -295,42 +282,28 @@ static int referenced_object(struct kmemleak_object *object)
 static int unreferenced_object(struct kmemleak_object *object)
 {
        return (object->flags & OBJECT_ALLOCATED) && color_white(object) &&
-               time_is_before_eq_jiffies(object->jiffies + jiffies_min_age);
+               time_before_eq(object->jiffies + jiffies_min_age,
+                              jiffies_last_scan);
 }
 
 /*
- * Printing of the (un)referenced objects information, either to the seq file
- * or to the kernel log. The print_referenced/print_unreferenced functions
- * must be called with the object->lock held.
+ * Printing of the unreferenced objects information to the seq file. The
+ * print_unreferenced function must be called with the object->lock held.
  */
-#define print_helper(seq, x...)        do {    \
-       struct seq_file *s = (seq);     \
-       if (s)                          \
-               seq_printf(s, x);       \
-       else                            \
-               pr_info(x);             \
-} while (0)
-
-static void print_referenced(struct kmemleak_object *object)
-{
-       pr_info("referenced object 0x%08lx (size %zu)\n",
-               object->pointer, object->size);
-}
-
 static void print_unreferenced(struct seq_file *seq,
                               struct kmemleak_object *object)
 {
        int i;
 
-       print_helper(seq, "unreferenced object 0x%08lx (size %zu):\n",
-                    object->pointer, object->size);
-       print_helper(seq, "  comm \"%s\", pid %d, jiffies %lu\n",
-                    object->comm, object->pid, object->jiffies);
-       print_helper(seq, "  backtrace:\n");
+       seq_printf(seq, "unreferenced object 0x%08lx (size %zu):\n",
+                  object->pointer, object->size);
+       seq_printf(seq, "  comm \"%s\", pid %d, jiffies %lu\n",
+                  object->comm, object->pid, object->jiffies);
+       seq_printf(seq, "  backtrace:\n");
 
        for (i = 0; i < object->trace_len; i++) {
                void *ptr = (void *)object->trace[i];
-               print_helper(seq, "    [<%p>] %pS\n", ptr, ptr);
+               seq_printf(seq, "    [<%p>] %pS\n", ptr, ptr);
        }
 }
 
@@ -554,8 +527,10 @@ static void delete_object(unsigned long ptr)
        write_lock_irqsave(&kmemleak_lock, flags);
        object = lookup_object(ptr, 0);
        if (!object) {
+#ifdef DEBUG
                kmemleak_warn("Freeing unknown object at 0x%08lx\n",
                              ptr);
+#endif
                write_unlock_irqrestore(&kmemleak_lock, flags);
                return;
        }
@@ -571,8 +546,6 @@ static void delete_object(unsigned long ptr)
         * cannot be freed when it is being scanned.
         */
        spin_lock_irqsave(&object->lock, flags);
-       if (object->flags & OBJECT_REPORTED)
-               print_referenced(object);
        object->flags &= ~OBJECT_ALLOCATED;
        spin_unlock_irqrestore(&object->lock, flags);
        put_object(object);
@@ -696,7 +669,8 @@ static void log_early(int op_type, const void *ptr, size_t size,
        struct early_log *log;
 
        if (crt_early_log >= ARRAY_SIZE(early_log)) {
-               kmemleak_stop("Early log buffer exceeded\n");
+               pr_warning("Early log buffer exceeded\n");
+               kmemleak_disable();
                return;
        }
 
@@ -808,21 +782,6 @@ void kmemleak_no_scan(const void *ptr)
 EXPORT_SYMBOL(kmemleak_no_scan);
 
 /*
- * Yield the CPU so that other tasks get a chance to run.  The yielding is
- * rate-limited to avoid excessive number of calls to the schedule() function
- * during memory scanning.
- */
-static void scan_yield(void)
-{
-       might_sleep();
-
-       if (time_is_before_eq_jiffies(next_scan_yield)) {
-               schedule();
-               next_scan_yield = jiffies + jiffies_scan_yield;
-       }
-}
-
-/*
  * Memory scanning is a long process and it needs to be interruptable. This
  * function checks whether such interrupt condition occured.
  */
@@ -862,15 +821,6 @@ static void scan_block(void *_start, void *_end,
                if (scan_should_stop())
                        break;
 
-               /*
-                * When scanning a memory block with a corresponding
-                * kmemleak_object, the CPU yielding is handled in the calling
-                * code since it holds the object->lock to avoid the block
-                * freeing.
-                */
-               if (!scanned)
-                       scan_yield();
-
                object = find_and_get_object(pointer, 1);
                if (!object)
                        continue;
@@ -952,6 +902,9 @@ static void kmemleak_scan(void)
        struct kmemleak_object *object, *tmp;
        struct task_struct *task;
        int i;
+       int new_leaks = 0;
+
+       jiffies_last_scan = jiffies;
 
        /* prepare the kmemleak_object's */
        rcu_read_lock();
@@ -1033,7 +986,7 @@ static void kmemleak_scan(void)
         */
        object = list_entry(gray_list.next, typeof(*object), gray_list);
        while (&object->gray_list != &gray_list) {
-               scan_yield();
+               cond_resched();
 
                /* may add new objects to the list */
                if (!scan_should_stop())
@@ -1049,6 +1002,32 @@ static void kmemleak_scan(void)
                object = tmp;
        }
        WARN_ON(!list_empty(&gray_list));
+
+       /*
+        * If scanning was stopped do not report any new unreferenced objects.
+        */
+       if (scan_should_stop())
+               return;
+
+       /*
+        * Scanning result reporting.
+        */
+       rcu_read_lock();
+       list_for_each_entry_rcu(object, &object_list, object_list) {
+               spin_lock_irqsave(&object->lock, flags);
+               if (unreferenced_object(object) &&
+                   !(object->flags & OBJECT_REPORTED)) {
+                       object->flags |= OBJECT_REPORTED;
+                       new_leaks++;
+               }
+               spin_unlock_irqrestore(&object->lock, flags);
+       }
+       rcu_read_unlock();
+
+       if (new_leaks)
+               pr_info("%d new suspected memory leaks (see "
+                       "/sys/kernel/debug/kmemleak)\n", new_leaks);
+
 }
 
 /*
@@ -1070,36 +1049,12 @@ static int kmemleak_scan_thread(void *arg)
        }
 
        while (!kthread_should_stop()) {
-               struct kmemleak_object *object;
                signed long timeout = jiffies_scan_wait;
 
                mutex_lock(&scan_mutex);
-
                kmemleak_scan();
-               reported_leaks = 0;
-
-               rcu_read_lock();
-               list_for_each_entry_rcu(object, &object_list, object_list) {
-                       unsigned long flags;
-
-                       if (reported_leaks >= REPORTS_NR)
-                               break;
-                       spin_lock_irqsave(&object->lock, flags);
-                       if (!(object->flags & OBJECT_REPORTED) &&
-                           unreferenced_object(object)) {
-                               print_unreferenced(NULL, object);
-                               object->flags |= OBJECT_REPORTED;
-                               reported_leaks++;
-                       } else if ((object->flags & OBJECT_REPORTED) &&
-                                  referenced_object(object)) {
-                               print_referenced(object);
-                               object->flags &= ~OBJECT_REPORTED;
-                       }
-                       spin_unlock_irqrestore(&object->lock, flags);
-               }
-               rcu_read_unlock();
-
                mutex_unlock(&scan_mutex);
+
                /* wait before the next scan */
                while (timeout && !kthread_should_stop())
                        timeout = schedule_timeout_interruptible(timeout);
@@ -1112,7 +1067,7 @@ static int kmemleak_scan_thread(void *arg)
 
 /*
  * Start the automatic memory scanning thread. This function must be called
- * with the kmemleak_mutex held.
+ * with the scan_mutex held.
  */
 void start_scan_thread(void)
 {
@@ -1127,7 +1082,7 @@ void start_scan_thread(void)
 
 /*
  * Stop the automatic memory scanning thread. This function must be called
- * with the kmemleak_mutex held.
+ * with the scan_mutex held.
  */
 void stop_scan_thread(void)
 {
@@ -1147,10 +1102,8 @@ static void *kmemleak_seq_start(struct seq_file *seq, loff_t *pos)
        struct kmemleak_object *object;
        loff_t n = *pos;
 
-       if (!n) {
-               kmemleak_scan();
+       if (!n)
                reported_leaks = 0;
-       }
        if (reported_leaks >= REPORTS_NR)
                return NULL;
 
@@ -1211,11 +1164,10 @@ static int kmemleak_seq_show(struct seq_file *seq, void *v)
        unsigned long flags;
 
        spin_lock_irqsave(&object->lock, flags);
-       if (!unreferenced_object(object))
-               goto out;
-       print_unreferenced(seq, object);
-       reported_leaks++;
-out:
+       if ((object->flags & OBJECT_REPORTED) && unreferenced_object(object)) {
+               print_unreferenced(seq, object);
+               reported_leaks++;
+       }
        spin_unlock_irqrestore(&object->lock, flags);
        return 0;
 }
@@ -1234,13 +1186,10 @@ static int kmemleak_open(struct inode *inode, struct file *file)
        if (!atomic_read(&kmemleak_enabled))
                return -EBUSY;
 
-       ret = mutex_lock_interruptible(&kmemleak_mutex);
+       ret = mutex_lock_interruptible(&scan_mutex);
        if (ret < 0)
                goto out;
        if (file->f_mode & FMODE_READ) {
-               ret = mutex_lock_interruptible(&scan_mutex);
-               if (ret < 0)
-                       goto kmemleak_unlock;
                ret = seq_open(file, &kmemleak_seq_ops);
                if (ret < 0)
                        goto scan_unlock;
@@ -1249,8 +1198,6 @@ static int kmemleak_open(struct inode *inode, struct file *file)
 
 scan_unlock:
        mutex_unlock(&scan_mutex);
-kmemleak_unlock:
-       mutex_unlock(&kmemleak_mutex);
 out:
        return ret;
 }
@@ -1259,11 +1206,9 @@ static int kmemleak_release(struct inode *inode, struct file *file)
 {
        int ret = 0;
 
-       if (file->f_mode & FMODE_READ) {
+       if (file->f_mode & FMODE_READ)
                seq_release(inode, file);
-               mutex_unlock(&scan_mutex);
-       }
-       mutex_unlock(&kmemleak_mutex);
+       mutex_unlock(&scan_mutex);
 
        return ret;
 }
@@ -1278,6 +1223,7 @@ static int kmemleak_release(struct inode *inode, struct file *file)
  *   scan=off  - stop the automatic memory scanning thread
  *   scan=...  - set the automatic memory scanning period in seconds (0 to
  *               disable it)
+ *   scan      - trigger a memory scan
  */
 static ssize_t kmemleak_write(struct file *file, const char __user *user_buf,
                              size_t size, loff_t *ppos)
@@ -1315,7 +1261,9 @@ static ssize_t kmemleak_write(struct file *file, const char __user *user_buf,
                        jiffies_scan_wait = msecs_to_jiffies(secs * 1000);
                        start_scan_thread();
                }
-       } else
+       } else if (strncmp(buf, "scan", 4) == 0)
+               kmemleak_scan();
+       else
                return -EINVAL;
 
        /* ignore the rest of the buffer, only one command at a time */
@@ -1340,11 +1288,9 @@ static int kmemleak_cleanup_thread(void *arg)
 {
        struct kmemleak_object *object;
 
-       mutex_lock(&kmemleak_mutex);
+       mutex_lock(&scan_mutex);
        stop_scan_thread();
-       mutex_unlock(&kmemleak_mutex);
 
-       mutex_lock(&scan_mutex);
        rcu_read_lock();
        list_for_each_entry_rcu(object, &object_list, object_list)
                delete_object(object->pointer);
@@ -1411,7 +1357,6 @@ void __init kmemleak_init(void)
        int i;
        unsigned long flags;
 
-       jiffies_scan_yield = msecs_to_jiffies(MSECS_SCAN_YIELD);
        jiffies_min_age = msecs_to_jiffies(MSECS_MIN_AGE);
        jiffies_scan_wait = msecs_to_jiffies(SECS_SCAN_WAIT * 1000);
 
@@ -1486,9 +1431,9 @@ static int __init kmemleak_late_init(void)
                                     &kmemleak_fops);
        if (!dentry)
                pr_warning("Failed to create the debugfs kmemleak file\n");
-       mutex_lock(&kmemleak_mutex);
+       mutex_lock(&scan_mutex);
        start_scan_thread();
-       mutex_unlock(&kmemleak_mutex);
+       mutex_unlock(&scan_mutex);
 
        pr_info("Kernel memory leak detector initialized\n");
 
index f46ac18..6521619 100644 (file)
@@ -1207,8 +1207,8 @@ static inline int use_zero_page(struct vm_area_struct *vma)
 
 
 int __get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
-                    unsigned long start, int len, int flags,
-               struct page **pages, struct vm_area_struct **vmas)
+                    unsigned long start, int nr_pages, int flags,
+                    struct page **pages, struct vm_area_struct **vmas)
 {
        int i;
        unsigned int vm_flags = 0;
@@ -1217,7 +1217,7 @@ int __get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
        int ignore = !!(flags & GUP_FLAGS_IGNORE_VMA_PERMISSIONS);
        int ignore_sigkill = !!(flags & GUP_FLAGS_IGNORE_SIGKILL);
 
-       if (len <= 0)
+       if (nr_pages <= 0)
                return 0;
        /* 
         * Require read or write permissions.
@@ -1269,7 +1269,7 @@ int __get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
                                vmas[i] = gate_vma;
                        i++;
                        start += PAGE_SIZE;
-                       len--;
+                       nr_pages--;
                        continue;
                }
 
@@ -1280,7 +1280,7 @@ int __get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
 
                if (is_vm_hugetlb_page(vma)) {
                        i = follow_hugetlb_page(mm, vma, pages, vmas,
-                                               &start, &len, i, write);
+                                               &start, &nr_pages, i, write);
                        continue;
                }
 
@@ -1357,9 +1357,9 @@ int __get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
                                vmas[i] = vma;
                        i++;
                        start += PAGE_SIZE;
-                       len--;
-               } while (len && start < vma->vm_end);
-       } while (len);
+                       nr_pages--;
+               } while (nr_pages && start < vma->vm_end);
+       } while (nr_pages);
        return i;
 }
 
@@ -1368,7 +1368,7 @@ int __get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
  * @tsk:       task_struct of target task
  * @mm:                mm_struct of target mm
  * @start:     starting user address
- * @len:       number of pages from start to pin
+ * @nr_pages:  number of pages from start to pin
  * @write:     whether pages will be written to by the caller
  * @force:     whether to force write access even if user mapping is
  *             readonly. This will result in the page being COWed even
@@ -1380,7 +1380,7 @@ int __get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
  *             Or NULL if the caller does not require them.
  *
  * Returns number of pages pinned. This may be fewer than the number
- * requested. If len is 0 or negative, returns 0. If no pages
+ * requested. If nr_pages is 0 or negative, returns 0. If no pages
  * were pinned, returns -errno. Each page returned must be released
  * with a put_page() call when it is finished with. vmas will only
  * remain valid while mmap_sem is held.
@@ -1414,7 +1414,7 @@ int __get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
  * See also get_user_pages_fast, for performance critical applications.
  */
 int get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
-               unsigned long start, int len, int write, int force,
+               unsigned long start, int nr_pages, int write, int force,
                struct page **pages, struct vm_area_struct **vmas)
 {
        int flags = 0;
@@ -1424,9 +1424,7 @@ int get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
        if (force)
                flags |= GUP_FLAGS_FORCE;
 
-       return __get_user_pages(tsk, mm,
-                               start, len, flags,
-                               pages, vmas);
+       return __get_user_pages(tsk, mm, start, nr_pages, flags, pages, vmas);
 }
 
 EXPORT_SYMBOL(get_user_pages);
index 2fd2ad5..53cab10 100644 (file)
@@ -173,8 +173,8 @@ unsigned int kobjsize(const void *objp)
 }
 
 int __get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
-                    unsigned long start, int len, int flags,
-               struct page **pages, struct vm_area_struct **vmas)
+                    unsigned long start, int nr_pages, int flags,
+                    struct page **pages, struct vm_area_struct **vmas)
 {
        struct vm_area_struct *vma;
        unsigned long vm_flags;
@@ -189,7 +189,7 @@ int __get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
        vm_flags  = write ? (VM_WRITE | VM_MAYWRITE) : (VM_READ | VM_MAYREAD);
        vm_flags &= force ? (VM_MAYREAD | VM_MAYWRITE) : (VM_READ | VM_WRITE);
 
-       for (i = 0; i < len; i++) {
+       for (i = 0; i < nr_pages; i++) {
                vma = find_vma(mm, start);
                if (!vma)
                        goto finish_or_fault;
@@ -224,7 +224,7 @@ finish_or_fault:
  * - don't permit access to VMAs that don't support it, such as I/O mappings
  */
 int get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
-       unsigned long start, int len, int write, int force,
+       unsigned long start, int nr_pages, int write, int force,
        struct page **pages, struct vm_area_struct **vmas)
 {
        int flags = 0;
@@ -234,12 +234,31 @@ int get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
        if (force)
                flags |= GUP_FLAGS_FORCE;
 
-       return __get_user_pages(tsk, mm,
-                               start, len, flags,
-                               pages, vmas);
+       return __get_user_pages(tsk, mm, start, nr_pages, flags, pages, vmas);
 }
 EXPORT_SYMBOL(get_user_pages);
 
+/**
+ * follow_pfn - look up PFN at a user virtual address
+ * @vma: memory mapping
+ * @address: user virtual address
+ * @pfn: location to store found PFN
+ *
+ * Only IO mappings and raw PFN mappings are allowed.
+ *
+ * Returns zero and the pfn at @pfn on success, -ve otherwise.
+ */
+int follow_pfn(struct vm_area_struct *vma, unsigned long address,
+       unsigned long *pfn)
+{
+       if (!(vma->vm_flags & (VM_IO | VM_PFNMAP)))
+               return -EINVAL;
+
+       *pfn = address >> PAGE_SHIFT;
+       return 0;
+}
+EXPORT_SYMBOL(follow_pfn);
+
 DEFINE_RWLOCK(vmlist_lock);
 struct vm_struct *vmlist;
 
index 7b0dcea..7687879 100644 (file)
@@ -541,8 +541,11 @@ static void balance_dirty_pages(struct address_space *mapping)
                 * filesystems (i.e. NFS) in which data may have been
                 * written to the server's write cache, but has not yet
                 * been flushed to permanent storage.
+                * Only move pages to writeback if this bdi is over its
+                * threshold otherwise wait until the disk writes catch
+                * up.
                 */
-               if (bdi_nr_reclaimable) {
+               if (bdi_nr_reclaimable > bdi_thresh) {
                        writeback_inodes(&wbc);
                        pages_written += write_chunk - wbc.nr_to_write;
                        get_dirty_limits(&background_thresh, &dirty_thresh,
index 5d714f8..e0f2cdf 100644 (file)
@@ -4032,6 +4032,8 @@ static void __init find_zone_movable_pfns_for_nodes(unsigned long *movable_pfn)
        int i, nid;
        unsigned long usable_startpfn;
        unsigned long kernelcore_node, kernelcore_remaining;
+       /* save the state before borrow the nodemask */
+       nodemask_t saved_node_state = node_states[N_HIGH_MEMORY];
        unsigned long totalpages = early_calculate_totalpages();
        int usable_nodes = nodes_weight(node_states[N_HIGH_MEMORY]);
 
@@ -4059,7 +4061,7 @@ static void __init find_zone_movable_pfns_for_nodes(unsigned long *movable_pfn)
 
        /* If kernelcore was not specified, there is no ZONE_MOVABLE */
        if (!required_kernelcore)
-               return;
+               goto out;
 
        /* usable_startpfn is the lowest possible pfn ZONE_MOVABLE can be at */
        find_usable_zone_for_movable();
@@ -4158,6 +4160,10 @@ restart:
        for (nid = 0; nid < MAX_NUMNODES; nid++)
                zone_movable_pfn[nid] =
                        roundup(zone_movable_pfn[nid], MAX_ORDER_NR_PAGES);
+
+out:
+       /* restore the node_state */
+       node_states[N_HIGH_MEMORY] = saved_node_state;
 }
 
 /* Any regular memory on that node ? */
@@ -4242,11 +4248,6 @@ void __init free_area_init_nodes(unsigned long *max_zone_pfn)
                                                early_node_map[i].start_pfn,
                                                early_node_map[i].end_pfn);
 
-       /*
-        * find_zone_movable_pfns_for_nodes/early_calculate_totalpages init
-        * that node_mask, clear it at first
-        */
-       nodes_clear(node_states[N_HIGH_MEMORY]);
        /* Initialise every node */
        mminit_verify_pageflags_layout();
        setup_nr_node_ids();
index c0b2c1a..b70f2ac 100644 (file)
@@ -549,14 +549,14 @@ static void pcpu_free_area(struct pcpu_chunk *chunk, int freeme)
  * @chunk: chunk of interest
  * @page_start: page index of the first page to unmap
  * @page_end: page index of the last page to unmap + 1
- * @flush: whether to flush cache and tlb or not
+ * @flush_tlb: whether to flush tlb or not
  *
  * For each cpu, unmap pages [@page_start,@page_end) out of @chunk.
  * If @flush is true, vcache is flushed before unmapping and tlb
  * after.
  */
 static void pcpu_unmap(struct pcpu_chunk *chunk, int page_start, int page_end,
-                      bool flush)
+                      bool flush_tlb)
 {
        unsigned int last = num_possible_cpus() - 1;
        unsigned int cpu;
@@ -569,9 +569,8 @@ static void pcpu_unmap(struct pcpu_chunk *chunk, int page_start, int page_end,
         * the whole region at once rather than doing it for each cpu.
         * This could be an overkill but is more scalable.
         */
-       if (flush)
-               flush_cache_vunmap(pcpu_chunk_addr(chunk, 0, page_start),
-                                  pcpu_chunk_addr(chunk, last, page_end));
+       flush_cache_vunmap(pcpu_chunk_addr(chunk, 0, page_start),
+                          pcpu_chunk_addr(chunk, last, page_end));
 
        for_each_possible_cpu(cpu)
                unmap_kernel_range_noflush(
@@ -579,7 +578,7 @@ static void pcpu_unmap(struct pcpu_chunk *chunk, int page_start, int page_end,
                                (page_end - page_start) << PAGE_SHIFT);
 
        /* ditto as flush_cache_vunmap() */
-       if (flush)
+       if (flush_tlb)
                flush_tlb_kernel_range(pcpu_chunk_addr(chunk, 0, page_start),
                                       pcpu_chunk_addr(chunk, last, page_end));
 }
@@ -1234,6 +1233,7 @@ static struct page * __init pcpue_get_page(unsigned int cpu, int pageno)
 ssize_t __init pcpu_embed_first_chunk(size_t static_size, size_t reserved_size,
                                      ssize_t dyn_size, ssize_t unit_size)
 {
+       size_t chunk_size;
        unsigned int cpu;
 
        /* determine parameters and allocate */
@@ -1248,11 +1248,15 @@ ssize_t __init pcpu_embed_first_chunk(size_t static_size, size_t reserved_size,
        } else
                pcpue_unit_size = max_t(size_t, pcpue_size, PCPU_MIN_UNIT_SIZE);
 
-       pcpue_ptr = __alloc_bootmem_nopanic(
-                                       num_possible_cpus() * pcpue_unit_size,
-                                       PAGE_SIZE, __pa(MAX_DMA_ADDRESS));
-       if (!pcpue_ptr)
+       chunk_size = pcpue_unit_size * num_possible_cpus();
+
+       pcpue_ptr = __alloc_bootmem_nopanic(chunk_size, PAGE_SIZE,
+                                           __pa(MAX_DMA_ADDRESS));
+       if (!pcpue_ptr) {
+               pr_warning("PERCPU: failed to allocate %zu bytes for "
+                          "embedding\n", chunk_size);
                return -ENOMEM;
+       }
 
        /* return the leftover and copy */
        for_each_possible_cpu(cpu) {
index fe64908..6d37b7e 100644 (file)
@@ -468,6 +468,19 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event,
                }
                break;
 
+       case NETDEV_CHANGEMTU:
+               for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) {
+                       vlandev = vlan_group_get_device(grp, i);
+                       if (!vlandev)
+                               continue;
+
+                       if (vlandev->mtu <= dev->mtu)
+                               continue;
+
+                       dev_set_mtu(vlandev, dev->mtu);
+               }
+               break;
+
        case NETDEV_FEAT_CHANGE:
                /* Propagate device features to underlying device */
                for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) {
index 7051b97..041c35e 100644 (file)
@@ -23,6 +23,26 @@ menuconfig NET
 
 if NET
 
+config WANT_COMPAT_NETLINK_MESSAGES
+       bool
+       help
+         This option can be selected by other options that need compat
+         netlink messages.
+
+config COMPAT_NETLINK_MESSAGES
+       def_bool y
+       depends on COMPAT
+       depends on WIRELESS_EXT || WANT_COMPAT_NETLINK_MESSAGES
+       help
+         This option makes it possible to send different netlink messages
+         to tasks depending on whether the task is a compat task or not. To
+         achieve this, you need to set skb_shinfo(skb)->frag_list to the
+         compat skb before sending the skb, the netlink code will sort out
+         which message to actually pass to the task.
+
+         Newly written code should NEVER need this option but do
+         compat-independent messages instead!
+
 menu "Networking options"
 
 source "net/packet/Kconfig"
index ba324ae..1542e72 100644 (file)
@@ -24,7 +24,6 @@ obj-y                         += ipv6/
 endif
 obj-$(CONFIG_PACKET)           += packet/
 obj-$(CONFIG_NET_KEY)          += key/
-obj-$(CONFIG_NET_SCHED)                += sched/
 obj-$(CONFIG_BRIDGE)           += bridge/
 obj-$(CONFIG_NET_DSA)          += dsa/
 obj-$(CONFIG_IPX)              += ipx/
index 2912665..848af11 100644 (file)
@@ -238,7 +238,7 @@ static int br2684_start_xmit(struct sk_buff *skb, struct net_device *dev)
                /* netif_stop_queue(dev); */
                dev_kfree_skb(skb);
                read_unlock(&devs_lock);
-               return 0;
+               return NETDEV_TX_OK;
        }
        if (!br2684_xmit_vcc(skb, dev, brvcc)) {
                /*
@@ -252,7 +252,7 @@ static int br2684_start_xmit(struct sk_buff *skb, struct net_device *dev)
                dev->stats.tx_fifo_errors++;
        }
        read_unlock(&devs_lock);
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 /*
index e65a3b1..64910bb 100644 (file)
@@ -373,7 +373,7 @@ static int clip_start_xmit(struct sk_buff *skb, struct net_device *dev)
                printk(KERN_ERR "clip_start_xmit: skb_dst(skb) == NULL\n");
                dev_kfree_skb(skb);
                dev->stats.tx_dropped++;
-               return 0;
+               return NETDEV_TX_OK;
        }
        if (!skb_dst(skb)->neighbour) {
 #if 0
@@ -387,7 +387,7 @@ static int clip_start_xmit(struct sk_buff *skb, struct net_device *dev)
                printk(KERN_ERR "clip_start_xmit: NO NEIGHBOUR !\n");
                dev_kfree_skb(skb);
                dev->stats.tx_dropped++;
-               return 0;
+               return NETDEV_TX_OK;
        }
        entry = NEIGH2ENTRY(skb_dst(skb)->neighbour);
        if (!entry->vccs) {
@@ -402,7 +402,7 @@ static int clip_start_xmit(struct sk_buff *skb, struct net_device *dev)
                        dev_kfree_skb(skb);
                        dev->stats.tx_dropped++;
                }
-               return 0;
+               return NETDEV_TX_OK;
        }
        pr_debug("neigh %p, vccs %p\n", entry, entry->vccs);
        ATM_SKB(skb)->vcc = vcc = entry->vccs->vcc;
@@ -421,14 +421,14 @@ static int clip_start_xmit(struct sk_buff *skb, struct net_device *dev)
        old = xchg(&entry->vccs->xoff, 1);      /* assume XOFF ... */
        if (old) {
                printk(KERN_WARNING "clip_start_xmit: XOFF->XOFF transition\n");
-               return 0;
+               return NETDEV_TX_OK;
        }
        dev->stats.tx_packets++;
        dev->stats.tx_bytes += skb->len;
        vcc->send(vcc, skb);
        if (atm_may_send(vcc, 0)) {
                entry->vccs->xoff = 0;
-               return 0;
+               return NETDEV_TX_OK;
        }
        spin_lock_irqsave(&clip_priv->xoff_lock, flags);
        netif_stop_queue(dev);  /* XOFF -> throttle immediately */
@@ -440,7 +440,7 @@ static int clip_start_xmit(struct sk_buff *skb, struct net_device *dev)
           of the brief netif_stop_queue. If this isn't true or if it
           changes, use netif_wake_queue instead. */
        spin_unlock_irqrestore(&clip_priv->xoff_lock, flags);
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 static int clip_mkip(struct atm_vcc *vcc, int timeout)
index ff2e594..c463868 100644 (file)
@@ -289,7 +289,7 @@ static int lec_start_xmit(struct sk_buff *skb, struct net_device *dev)
                skb2 = skb_realloc_headroom(skb, LEC_HEADER_LEN);
                kfree_skb(skb);
                if (skb2 == NULL)
-                       return 0;
+                       return NETDEV_TX_OK;
                skb = skb2;
        }
        skb_push(skb, 2);
@@ -307,7 +307,7 @@ static int lec_start_xmit(struct sk_buff *skb, struct net_device *dev)
                skb2 = skb_realloc_headroom(skb, LEC_HEADER_LEN);
                kfree_skb(skb);
                if (skb2 == NULL)
-                       return 0;
+                       return NETDEV_TX_OK;
                skb = skb2;
        }
 #endif
@@ -345,7 +345,7 @@ static int lec_start_xmit(struct sk_buff *skb, struct net_device *dev)
                        dev_kfree_skb(skb);
                        if (skb2 == NULL) {
                                dev->stats.tx_dropped++;
-                               return 0;
+                               return NETDEV_TX_OK;
                        }
                        skb = skb2;
                }
@@ -416,7 +416,7 @@ out:
        if (entry)
                lec_arp_put(entry);
        dev->trans_start = jiffies;
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 /* The inverse routine to net_open(). */
index e5bf114..1ac4b94 100644 (file)
@@ -554,7 +554,7 @@ static int mpc_send_packet(struct sk_buff *skb, struct net_device *dev)
        while (i < mpc->number_of_mps_macs) {
                if (!compare_ether_addr(eth->h_dest, (mpc->mps_macs + i*ETH_ALEN)))
                        if ( send_via_shortcut(skb, mpc) == 0 )           /* try shortcut */
-                               return 0;                                 /* success!     */
+                               return NETDEV_TX_OK;                      /* success!     */
                i++;
        }
 
index d7a0e97..9c42990 100644 (file)
@@ -175,14 +175,14 @@ static int bnep_net_xmit(struct sk_buff *skb, struct net_device *dev)
 #ifdef CONFIG_BT_BNEP_MC_FILTER
        if (bnep_net_mc_filter(skb, s)) {
                kfree_skb(skb);
-               return 0;
+               return NETDEV_TX_OK;
        }
 #endif
 
 #ifdef CONFIG_BT_BNEP_PROTO_FILTER
        if (bnep_net_proto_filter(skb, s)) {
                kfree_skb(skb);
-               return 0;
+               return NETDEV_TX_OK;
        }
 #endif
 
@@ -203,7 +203,7 @@ static int bnep_net_xmit(struct sk_buff *skb, struct net_device *dev)
                netif_stop_queue(dev);
        }
 
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 static const struct net_device_ops bnep_netdev_ops = {
index 18538d7..15d43ba 100644 (file)
@@ -39,7 +39,7 @@ int br_dev_xmit(struct sk_buff *skb, struct net_device *dev)
        else
                br_flood_deliver(br, skb);
 
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 static int br_dev_open(struct net_device *dev)
index d22f611..4fde742 100644 (file)
@@ -905,46 +905,62 @@ static unsigned int ip_sabotage_in(unsigned int hook, struct sk_buff *skb,
  * For br_nf_post_routing, we need (prio = NF_BR_PRI_LAST), because
  * ip_refrag() can return NF_STOLEN. */
 static struct nf_hook_ops br_nf_ops[] __read_mostly = {
-       { .hook = br_nf_pre_routing,
-         .owner = THIS_MODULE,
-         .pf = PF_BRIDGE,
-         .hooknum = NF_BR_PRE_ROUTING,
-         .priority = NF_BR_PRI_BRNF, },
-       { .hook = br_nf_local_in,
-         .owner = THIS_MODULE,
-         .pf = PF_BRIDGE,
-         .hooknum = NF_BR_LOCAL_IN,
-         .priority = NF_BR_PRI_BRNF, },
-       { .hook = br_nf_forward_ip,
-         .owner = THIS_MODULE,
-         .pf = PF_BRIDGE,
-         .hooknum = NF_BR_FORWARD,
-         .priority = NF_BR_PRI_BRNF - 1, },
-       { .hook = br_nf_forward_arp,
-         .owner = THIS_MODULE,
-         .pf = PF_BRIDGE,
-         .hooknum = NF_BR_FORWARD,
-         .priority = NF_BR_PRI_BRNF, },
-       { .hook = br_nf_local_out,
-         .owner = THIS_MODULE,
-         .pf = PF_BRIDGE,
-         .hooknum = NF_BR_LOCAL_OUT,
-         .priority = NF_BR_PRI_FIRST, },
-       { .hook = br_nf_post_routing,
-         .owner = THIS_MODULE,
-         .pf = PF_BRIDGE,
-         .hooknum = NF_BR_POST_ROUTING,
-         .priority = NF_BR_PRI_LAST, },
-       { .hook = ip_sabotage_in,
-         .owner = THIS_MODULE,
-         .pf = PF_INET,
-         .hooknum = NF_INET_PRE_ROUTING,
-         .priority = NF_IP_PRI_FIRST, },
-       { .hook = ip_sabotage_in,
-         .owner = THIS_MODULE,
-         .pf = PF_INET6,
-         .hooknum = NF_INET_PRE_ROUTING,
-         .priority = NF_IP6_PRI_FIRST, },
+       {
+               .hook = br_nf_pre_routing,
+               .owner = THIS_MODULE,
+               .pf = PF_BRIDGE,
+               .hooknum = NF_BR_PRE_ROUTING,
+               .priority = NF_BR_PRI_BRNF,
+       },
+       {
+               .hook = br_nf_local_in,
+               .owner = THIS_MODULE,
+               .pf = PF_BRIDGE,
+               .hooknum = NF_BR_LOCAL_IN,
+               .priority = NF_BR_PRI_BRNF,
+       },
+       {
+               .hook = br_nf_forward_ip,
+               .owner = THIS_MODULE,
+               .pf = PF_BRIDGE,
+               .hooknum = NF_BR_FORWARD,
+               .priority = NF_BR_PRI_BRNF - 1,
+       },
+       {
+               .hook = br_nf_forward_arp,
+               .owner = THIS_MODULE,
+               .pf = PF_BRIDGE,
+               .hooknum = NF_BR_FORWARD,
+               .priority = NF_BR_PRI_BRNF,
+       },
+       {
+               .hook = br_nf_local_out,
+               .owner = THIS_MODULE,
+               .pf = PF_BRIDGE,
+               .hooknum = NF_BR_LOCAL_OUT,
+               .priority = NF_BR_PRI_FIRST,
+       },
+       {
+               .hook = br_nf_post_routing,
+               .owner = THIS_MODULE,
+               .pf = PF_BRIDGE,
+               .hooknum = NF_BR_POST_ROUTING,
+               .priority = NF_BR_PRI_LAST,
+       },
+       {
+               .hook = ip_sabotage_in,
+               .owner = THIS_MODULE,
+               .pf = PF_INET,
+               .hooknum = NF_INET_PRE_ROUTING,
+               .priority = NF_IP_PRI_FIRST,
+       },
+       {
+               .hook = ip_sabotage_in,
+               .owner = THIS_MODULE,
+               .pf = PF_INET6,
+               .hooknum = NF_INET_PRE_ROUTING,
+               .priority = NF_IP6_PRI_FIRST,
+       },
 };
 
 #ifdef CONFIG_SYSCTL
index 8d73905..12728b1 100644 (file)
@@ -743,6 +743,18 @@ asmlinkage long compat_sys_recvmsg(int fd, struct compat_msghdr __user *msg, uns
        return sys_recvmsg(fd, (struct msghdr __user *)msg, flags | MSG_CMSG_COMPAT);
 }
 
+asmlinkage long compat_sys_recv(int fd, void __user *buf, size_t len, unsigned flags)
+{
+       return sys_recv(fd, buf, len, flags | MSG_CMSG_COMPAT);
+}
+
+asmlinkage long compat_sys_recvfrom(int fd, void __user *buf, size_t len,
+                                   unsigned flags, struct sockaddr __user *addr,
+                                   int __user *addrlen)
+{
+       return sys_recvfrom(fd, buf, len, flags | MSG_CMSG_COMPAT, addr, addrlen);
+}
+
 asmlinkage long compat_sys_socketcall(int call, u32 __user *args)
 {
        int ret;
@@ -788,10 +800,11 @@ asmlinkage long compat_sys_socketcall(int call, u32 __user *args)
                ret = sys_sendto(a0, compat_ptr(a1), a[2], a[3], compat_ptr(a[4]), a[5]);
                break;
        case SYS_RECV:
-               ret = sys_recv(a0, compat_ptr(a1), a[2], a[3]);
+               ret = compat_sys_recv(a0, compat_ptr(a1), a[2], a[3]);
                break;
        case SYS_RECVFROM:
-               ret = sys_recvfrom(a0, compat_ptr(a1), a[2], a[3], compat_ptr(a[4]), compat_ptr(a[5]));
+               ret = compat_sys_recvfrom(a0, compat_ptr(a1), a[2], a[3],
+                                         compat_ptr(a[4]), compat_ptr(a[5]));
                break;
        case SYS_SHUTDOWN:
                ret = sys_shutdown(a0,a1);
index 70c27e0..dca8b50 100644 (file)
@@ -1704,7 +1704,7 @@ int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
                        skb_dst_drop(skb);
 
                rc = ops->ndo_start_xmit(skb, dev);
-               if (rc == 0)
+               if (rc == NETDEV_TX_OK)
                        txq_trans_update(txq);
                /*
                 * TODO: if skb_orphan() was called by
@@ -1730,7 +1730,7 @@ gso:
                skb->next = nskb->next;
                nskb->next = NULL;
                rc = ops->ndo_start_xmit(nskb, dev);
-               if (unlikely(rc)) {
+               if (unlikely(rc != NETDEV_TX_OK)) {
                        nskb->next = skb->next;
                        skb->next = nskb;
                        return rc;
@@ -1744,7 +1744,7 @@ gso:
 
 out_kfree_skb:
        kfree_skb(skb);
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 static u32 skb_tx_hashrnd;
index 163b4f5..c6f9ad8 100644 (file)
@@ -1316,7 +1316,7 @@ void pneigh_enqueue(struct neigh_table *tbl, struct neigh_parms *p,
 }
 EXPORT_SYMBOL(pneigh_enqueue);
 
-static inline struct neigh_parms *lookup_neigh_params(struct neigh_table *tbl,
+static inline struct neigh_parms *lookup_neigh_parms(struct neigh_table *tbl,
                                                      struct net *net, int ifindex)
 {
        struct neigh_parms *p;
@@ -1337,7 +1337,7 @@ struct neigh_parms *neigh_parms_alloc(struct net_device *dev,
        struct net *net = dev_net(dev);
        const struct net_device_ops *ops = dev->netdev_ops;
 
-       ref = lookup_neigh_params(tbl, net, 0);
+       ref = lookup_neigh_parms(tbl, net, 0);
        if (!ref)
                return NULL;
 
@@ -1906,7 +1906,7 @@ static int neightbl_set(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
                if (tbp[NDTPA_IFINDEX])
                        ifindex = nla_get_u32(tbp[NDTPA_IFINDEX]);
 
-               p = lookup_neigh_params(tbl, net, ifindex);
+               p = lookup_neigh_parms(tbl, net, ifindex);
                if (p == NULL) {
                        err = -ENOENT;
                        goto errout_tbl_lock;
index b7292a2..ddd2cd2 100644 (file)
@@ -6,6 +6,8 @@
 #include <linux/delay.h>
 #include <linux/sched.h>
 #include <linux/idr.h>
+#include <linux/rculist.h>
+#include <linux/nsproxy.h>
 #include <net/net_namespace.h>
 #include <net/netns/generic.h>
 
@@ -127,7 +129,7 @@ static struct net *net_create(void)
        rv = setup_net(net);
        if (rv == 0) {
                rtnl_lock();
-               list_add_tail(&net->list, &net_namespace_list);
+               list_add_tail_rcu(&net->list, &net_namespace_list);
                rtnl_unlock();
        }
        mutex_unlock(&net_mutex);
@@ -156,9 +158,16 @@ static void cleanup_net(struct work_struct *work)
 
        /* Don't let anyone else find us. */
        rtnl_lock();
-       list_del(&net->list);
+       list_del_rcu(&net->list);
        rtnl_unlock();
 
+       /*
+        * Another CPU might be rcu-iterating the list, wait for it.
+        * This needs to be before calling the exit() notifiers, so
+        * the rcu_barrier() below isn't sufficient alone.
+        */
+       synchronize_rcu();
+
        /* Run all of the network namespace exit methods */
        list_for_each_entry_reverse(ops, &pernet_list, list) {
                if (ops->exit)
@@ -193,6 +202,26 @@ struct net *copy_net_ns(unsigned long flags, struct net *old_net)
 }
 #endif
 
+struct net *get_net_ns_by_pid(pid_t pid)
+{
+       struct task_struct *tsk;
+       struct net *net;
+
+       /* Lookup the network namespace */
+       net = ERR_PTR(-ESRCH);
+       rcu_read_lock();
+       tsk = find_task_by_vpid(pid);
+       if (tsk) {
+               struct nsproxy *nsproxy;
+               nsproxy = task_nsproxy(tsk);
+               if (nsproxy)
+                       net = get_net(nsproxy->net_ns);
+       }
+       rcu_read_unlock();
+       return net;
+}
+EXPORT_SYMBOL_GPL(get_net_ns_by_pid);
+
 static int __init net_ns_init(void)
 {
        struct net_generic *ng;
@@ -219,7 +248,7 @@ static int __init net_ns_init(void)
                panic("Could not setup the initial network namespace");
 
        rtnl_lock();
-       list_add_tail(&init_net.list, &net_namespace_list);
+       list_add_tail_rcu(&init_net.list, &net_namespace_list);
        rtnl_unlock();
 
        mutex_unlock(&net_mutex);
index df30feb..0ac3091 100644 (file)
@@ -9,6 +9,7 @@
  * Copyright (C) 2002  Red Hat, Inc.
  */
 
+#include <linux/moduleparam.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/string.h>
@@ -50,6 +51,9 @@ static atomic_t trapped;
 static void zap_completion_queue(void);
 static void arp_reply(struct sk_buff *skb);
 
+static unsigned int carrier_timeout = 4;
+module_param(carrier_timeout, uint, 0644);
+
 static void queue_process(struct work_struct *work)
 {
        struct netpoll_info *npinfo =
@@ -732,7 +736,7 @@ int netpoll_setup(struct netpoll *np)
                }
 
                atleast = jiffies + HZ/10;
-               atmost = jiffies + 4*HZ;
+               atmost = jiffies + carrier_timeout * HZ;
                while (!netif_carrier_ok(ndev)) {
                        if (time_after(jiffies, atmost)) {
                                printk(KERN_NOTICE
index d78030f..b44775f 100644 (file)
@@ -35,7 +35,6 @@
 #include <linux/security.h>
 #include <linux/mutex.h>
 #include <linux/if_addr.h>
-#include <linux/nsproxy.h>
 
 #include <asm/uaccess.h>
 #include <asm/system.h>
@@ -52,6 +51,7 @@
 #include <net/pkt_sched.h>
 #include <net/fib_rules.h>
 #include <net/rtnetlink.h>
+#include <net/net_namespace.h>
 
 struct rtnl_link
 {
@@ -725,25 +725,6 @@ static const struct nla_policy ifla_info_policy[IFLA_INFO_MAX+1] = {
        [IFLA_INFO_DATA]        = { .type = NLA_NESTED },
 };
 
-static struct net *get_net_ns_by_pid(pid_t pid)
-{
-       struct task_struct *tsk;
-       struct net *net;
-
-       /* Lookup the network namespace */
-       net = ERR_PTR(-ESRCH);
-       rcu_read_lock();
-       tsk = find_task_by_vpid(pid);
-       if (tsk) {
-               struct nsproxy *nsproxy;
-               nsproxy = task_nsproxy(tsk);
-               if (nsproxy)
-                       net = get_net(nsproxy->net_ns);
-       }
-       rcu_read_unlock();
-       return net;
-}
-
 static int validate_linkmsg(struct net_device *dev, struct nlattr *tb[])
 {
        if (dev) {
index 1d6ca8a..9383d3e 100644 (file)
@@ -774,7 +774,7 @@ static int dn_rt_bug(struct sk_buff *skb)
 
        kfree_skb(skb);
 
-       return NET_RX_BAD;
+       return NET_RX_DROP;
 }
 
 static int dn_rt_set_next_hop(struct dn_route *rt, struct dn_fib_res *res)
index 2e1f836..e114da7 100644 (file)
@@ -1072,7 +1072,7 @@ static int econet_rcv(struct sk_buff *skb, struct net_device *dev, struct packet
                skb->protocol = htons(ETH_P_IP);
                skb_pull(skb, sizeof(struct ec_framehdr));
                netif_rx(skb);
-               return 0;
+               return NET_RX_SUCCESS;
        }
 
        sk = ec_listening_socket(hdr->port, hdr->src_stn, hdr->src_net);
@@ -1083,7 +1083,7 @@ static int econet_rcv(struct sk_buff *skb, struct net_device *dev, struct packet
                            hdr->port))
                goto drop;
 
-       return 0;
+       return NET_RX_SUCCESS;
 
 drop:
        kfree_skb(skb);
index 566ea6c..197d024 100644 (file)
@@ -1187,6 +1187,7 @@ static struct sk_buff *inet_gso_segment(struct sk_buff *skb, int features)
        int proto;
        int ihl;
        int id;
+       unsigned int offset = 0;
 
        if (!(features & NETIF_F_V4_CSUM))
                features &= ~NETIF_F_SG;
@@ -1229,7 +1230,14 @@ static struct sk_buff *inet_gso_segment(struct sk_buff *skb, int features)
        skb = segs;
        do {
                iph = ip_hdr(skb);
-               iph->id = htons(id++);
+               if (proto == IPPROTO_UDP) {
+                       iph->id = htons(id);
+                       iph->frag_off = htons(offset >> 3);
+                       if (skb->next != NULL)
+                               iph->frag_off |= htons(IP_MF);
+                       offset += (skb->len - skb->mac_len - iph->ihl * 4);
+               } else
+                       iph->id = htons(id++);
                iph->tot_len = htons(skb->len - skb->mac_len);
                iph->check = 0;
                iph->check = ip_fast_csum(skb_network_header(skb), iph->ihl);
@@ -1425,6 +1433,8 @@ static struct net_protocol tcp_protocol = {
 static struct net_protocol udp_protocol = {
        .handler =      udp_rcv,
        .err_handler =  udp_err,
+       .gso_send_check = udp4_ufo_send_check,
+       .gso_segment = udp4_ufo_fragment,
        .no_policy =    1,
        .netns_ok =     1,
 };
index 63c2fa7..d58b491 100644 (file)
@@ -164,6 +164,14 @@ static struct tnode *inflate(struct trie *t, struct tnode *tn);
 static struct tnode *halve(struct trie *t, struct tnode *tn);
 /* tnodes to free after resize(); protected by RTNL */
 static struct tnode *tnode_free_head;
+static size_t tnode_free_size;
+
+/*
+ * synchronize_rcu after call_rcu for that many pages; it should be especially
+ * useful before resizing the root node with PREEMPT_NONE configs; the value was
+ * obtained experimentally, aiming to avoid visible slowdown.
+ */
+static const int sync_pages = 128;
 
 static struct kmem_cache *fn_alias_kmem __read_mostly;
 static struct kmem_cache *trie_leaf_kmem __read_mostly;
@@ -319,6 +327,8 @@ static const int inflate_threshold = 50;
 static const int halve_threshold_root = 15;
 static const int inflate_threshold_root = 25;
 
+static int inflate_threshold_root_fix;
+#define INFLATE_FIX_MAX 10     /* a comment in resize() */
 
 static void __alias_free_mem(struct rcu_head *head)
 {
@@ -393,6 +403,8 @@ static void tnode_free_safe(struct tnode *tn)
        BUG_ON(IS_LEAF(tn));
        tn->tnode_free = tnode_free_head;
        tnode_free_head = tn;
+       tnode_free_size += sizeof(struct tnode) +
+                          (sizeof(struct node *) << tn->bits);
 }
 
 static void tnode_free_flush(void)
@@ -404,6 +416,11 @@ static void tnode_free_flush(void)
                tn->tnode_free = NULL;
                tnode_free(tn);
        }
+
+       if (tnode_free_size >= PAGE_SIZE * sync_pages) {
+               tnode_free_size = 0;
+               synchronize_rcu();
+       }
 }
 
 static struct leaf *leaf_new(void)
@@ -602,7 +619,8 @@ static struct node *resize(struct trie *t, struct tnode *tn)
        /* Keep root node larger  */
 
        if (!tn->parent)
-               inflate_threshold_use = inflate_threshold_root;
+               inflate_threshold_use = inflate_threshold_root +
+                                       inflate_threshold_root_fix;
        else
                inflate_threshold_use = inflate_threshold;
 
@@ -626,15 +644,27 @@ static struct node *resize(struct trie *t, struct tnode *tn)
        }
 
        if (max_resize < 0) {
-               if (!tn->parent)
-                       pr_warning("Fix inflate_threshold_root."
-                                  " Now=%d size=%d bits\n",
-                                  inflate_threshold_root, tn->bits);
-               else
+               if (!tn->parent) {
+                       /*
+                        * It was observed that during large updates even
+                        * inflate_threshold_root = 35 might be needed to avoid
+                        * this warning; but it should be temporary, so let's
+                        * try to handle this automatically.
+                        */
+                       if (inflate_threshold_root_fix < INFLATE_FIX_MAX)
+                               inflate_threshold_root_fix++;
+                       else
+                               pr_warning("Fix inflate_threshold_root."
+                                          " Now=%d size=%d bits fix=%d\n",
+                                          inflate_threshold_root, tn->bits,
+                                          inflate_threshold_root_fix);
+               } else {
                        pr_warning("Fix inflate_threshold."
                                   " Now=%d size=%d bits\n",
                                   inflate_threshold, tn->bits);
-       }
+               }
+       } else if (max_resize > 3 && !tn->parent && inflate_threshold_root_fix)
+               inflate_threshold_root_fix--;
 
        check_tnode(tn);
 
@@ -1435,7 +1465,7 @@ static int fn_trie_lookup(struct fib_table *tb, const struct flowi *flp,
                        cindex = tkey_extract_bits(mask_pfx(key, current_prefix_length),
                                                   pos, bits);
 
-               n = tnode_get_child(pn, cindex);
+               n = tnode_get_child_rcu(pn, cindex);
 
                if (n == NULL) {
 #ifdef CONFIG_IP_FIB_TRIE_STATS
@@ -1570,7 +1600,7 @@ backtrace:
                if (chopped_off <= pn->bits) {
                        cindex &= ~(1 << (chopped_off-1));
                } else {
-                       struct tnode *parent = node_parent((struct node *) pn);
+                       struct tnode *parent = node_parent_rcu((struct node *) pn);
                        if (!parent)
                                goto failed;
 
@@ -1783,7 +1813,7 @@ static struct leaf *trie_firstleaf(struct trie *t)
 static struct leaf *trie_nextleaf(struct leaf *l)
 {
        struct node *c = (struct node *) l;
-       struct tnode *p = node_parent(c);
+       struct tnode *p = node_parent_rcu(c);
 
        if (!p)
                return NULL;    /* trie with just one leaf */
index cb4a0f4..b902ef5 100644 (file)
@@ -821,7 +821,7 @@ static int ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
                        stats->tx_dropped++;
                        dev_kfree_skb(skb);
                        tunnel->recursion--;
-                       return 0;
+                       return NETDEV_TX_OK;
                }
                if (skb->sk)
                        skb_set_owner_w(new_skb, skb->sk);
@@ -889,7 +889,7 @@ static int ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
 
        IPTUNNEL_XMIT();
        tunnel->recursion--;
-       return 0;
+       return NETDEV_TX_OK;
 
 tx_error_icmp:
        dst_link_failure(skb);
@@ -898,7 +898,7 @@ tx_error:
        stats->tx_errors++;
        dev_kfree_skb(skb);
        tunnel->recursion--;
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 static int ipgre_tunnel_bind_dev(struct net_device *dev)
index 93e2b78..98075b6 100644 (file)
@@ -486,7 +486,7 @@ static int ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
                        stats->tx_dropped++;
                        dev_kfree_skb(skb);
                        tunnel->recursion--;
-                       return 0;
+                       return NETDEV_TX_OK;
                }
                if (skb->sk)
                        skb_set_owner_w(new_skb, skb->sk);
@@ -524,7 +524,7 @@ static int ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
 
        IPTUNNEL_XMIT();
        tunnel->recursion--;
-       return 0;
+       return NETDEV_TX_OK;
 
 tx_error_icmp:
        dst_link_failure(skb);
@@ -532,7 +532,7 @@ tx_error:
        stats->tx_errors++;
        dev_kfree_skb(skb);
        tunnel->recursion--;
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 static void ipip_tunnel_bind_dev(struct net_device *dev)
index 9a8da5e..06c33fb 100644 (file)
@@ -212,7 +212,7 @@ static int reg_vif_xmit(struct sk_buff *skb, struct net_device *dev)
                          IGMPMSG_WHOLEPKT);
        read_unlock(&mrt_lock);
        kfree_skb(skb);
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 static const struct net_device_ops reg_vif_netdev_ops = {
index bd62712..4e00442 100644 (file)
@@ -59,6 +59,7 @@ int sysctl_tcp_base_mss __read_mostly = 512;
 /* By default, RFC2861 behavior.  */
 int sysctl_tcp_slow_start_after_idle __read_mostly = 1;
 
+/* Account for new data that has been sent to the network. */
 static void tcp_event_new_data_sent(struct sock *sk, struct sk_buff *skb)
 {
        struct tcp_sock *tp = tcp_sk(sk);
@@ -142,6 +143,7 @@ static void tcp_cwnd_restart(struct sock *sk, struct dst_entry *dst)
        tp->snd_cwnd_used = 0;
 }
 
+/* Congestion state accounting after a packet has been sent. */
 static void tcp_event_data_sent(struct tcp_sock *tp,
                                struct sk_buff *skb, struct sock *sk)
 {
@@ -161,6 +163,7 @@ static void tcp_event_data_sent(struct tcp_sock *tp,
                icsk->icsk_ack.pingpong = 1;
 }
 
+/* Account for an ACK we sent. */
 static inline void tcp_event_ack_sent(struct sock *sk, unsigned int pkts)
 {
        tcp_dec_quickack_mode(sk, pkts);
@@ -276,6 +279,7 @@ static u16 tcp_select_window(struct sock *sk)
        return new_win;
 }
 
+/* Packet ECN state for a SYN-ACK */
 static inline void TCP_ECN_send_synack(struct tcp_sock *tp, struct sk_buff *skb)
 {
        TCP_SKB_CB(skb)->flags &= ~TCPCB_FLAG_CWR;
@@ -283,6 +287,7 @@ static inline void TCP_ECN_send_synack(struct tcp_sock *tp, struct sk_buff *skb)
                TCP_SKB_CB(skb)->flags &= ~TCPCB_FLAG_ECE;
 }
 
+/* Packet ECN state for a SYN.  */
 static inline void TCP_ECN_send_syn(struct sock *sk, struct sk_buff *skb)
 {
        struct tcp_sock *tp = tcp_sk(sk);
@@ -301,6 +306,9 @@ TCP_ECN_make_synack(struct request_sock *req, struct tcphdr *th)
                th->ece = 1;
 }
 
+/* Set up ECN state for a packet on a ESTABLISHED socket that is about to
+ * be sent.
+ */
 static inline void TCP_ECN_send(struct sock *sk, struct sk_buff *skb,
                                int tcp_header_len)
 {
@@ -362,7 +370,9 @@ struct tcp_out_options {
        __u32 tsval, tsecr;     /* need to include OPTION_TS */
 };
 
-/* Beware: Something in the Internet is very sensitive to the ordering of
+/* Write previously computed TCP options to the packet.
+ *
+ * Beware: Something in the Internet is very sensitive to the ordering of
  * TCP options, we learned this through the hard way, so be careful here.
  * Luckily we can at least blame others for their non-compliance but from
  * inter-operatibility perspective it seems that we're somewhat stuck with
@@ -445,6 +455,9 @@ static void tcp_options_write(__be32 *ptr, struct tcp_sock *tp,
        }
 }
 
+/* Compute TCP options for SYN packets. This is not the final
+ * network wire format yet.
+ */
 static unsigned tcp_syn_options(struct sock *sk, struct sk_buff *skb,
                                struct tcp_out_options *opts,
                                struct tcp_md5sig_key **md5) {
@@ -493,6 +506,7 @@ static unsigned tcp_syn_options(struct sock *sk, struct sk_buff *skb,
        return size;
 }
 
+/* Set up TCP options for SYN-ACKs. */
 static unsigned tcp_synack_options(struct sock *sk,
                                   struct request_sock *req,
                                   unsigned mss, struct sk_buff *skb,
@@ -541,6 +555,9 @@ static unsigned tcp_synack_options(struct sock *sk,
        return size;
 }
 
+/* Compute TCP options for ESTABLISHED sockets. This is not the
+ * final wire format yet.
+ */
 static unsigned tcp_established_options(struct sock *sk, struct sk_buff *skb,
                                        struct tcp_out_options *opts,
                                        struct tcp_md5sig_key **md5) {
@@ -705,7 +722,7 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it,
        return net_xmit_eval(err);
 }
 
-/* This routine just queue's the buffer
+/* This routine just queues the buffer for sending.
  *
  * NOTE: probe0 timer is not checked, do not forget tcp_push_pending_frames,
  * otherwise socket can stall.
@@ -722,6 +739,7 @@ static void tcp_queue_skb(struct sock *sk, struct sk_buff *skb)
        sk_mem_charge(sk, skb->truesize);
 }
 
+/* Initialize TSO segments for a packet. */
 static void tcp_set_skb_tso_segs(struct sock *sk, struct sk_buff *skb,
                                 unsigned int mss_now)
 {
@@ -909,6 +927,7 @@ static void __pskb_trim_head(struct sk_buff *skb, int len)
        skb->len = skb->data_len;
 }
 
+/* Remove acked data from a packet in the transmit queue. */
 int tcp_trim_head(struct sock *sk, struct sk_buff *skb, u32 len)
 {
        if (skb_cloned(skb) && pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
@@ -937,7 +956,7 @@ int tcp_trim_head(struct sock *sk, struct sk_buff *skb, u32 len)
        return 0;
 }
 
-/* Not accounting for SACKs here. */
+/* Calculate MSS. Not accounting for SACKs here.  */
 int tcp_mtu_to_mss(struct sock *sk, int pmtu)
 {
        struct tcp_sock *tp = tcp_sk(sk);
@@ -981,6 +1000,7 @@ int tcp_mss_to_mtu(struct sock *sk, int mss)
        return mtu;
 }
 
+/* MTU probing init per socket */
 void tcp_mtup_init(struct sock *sk)
 {
        struct tcp_sock *tp = tcp_sk(sk);
@@ -1143,7 +1163,8 @@ static inline unsigned int tcp_cwnd_test(struct tcp_sock *tp,
        return 0;
 }
 
-/* This must be invoked the first time we consider transmitting
+/* Intialize TSO state of a skb.
+ * This must be invoked the first time we consider transmitting
  * SKB onto the wire.
  */
 static int tcp_init_tso_segs(struct sock *sk, struct sk_buff *skb,
@@ -1158,6 +1179,7 @@ static int tcp_init_tso_segs(struct sock *sk, struct sk_buff *skb,
        return tso_segs;
 }
 
+/* Minshall's variant of the Nagle send check. */
 static inline int tcp_minshall_check(const struct tcp_sock *tp)
 {
        return after(tp->snd_sml, tp->snd_una) &&
@@ -1242,6 +1264,7 @@ static unsigned int tcp_snd_test(struct sock *sk, struct sk_buff *skb,
        return cwnd_quota;
 }
 
+/* Test if sending is allowed right now. */
 int tcp_may_send_now(struct sock *sk)
 {
        struct tcp_sock *tp = tcp_sk(sk);
@@ -1378,6 +1401,10 @@ send_now:
 }
 
 /* Create a new MTU probe if we are ready.
+ * MTU probe is regularly attempting to increase the path MTU by
+ * deliberately sending larger packets.  This discovers routing
+ * changes resulting in larger path MTUs.
+ *
  * Returns 0 if we should wait to probe (no cwnd available),
  *         1 if a probe was sent,
  *         -1 otherwise
@@ -1790,6 +1817,7 @@ static void tcp_collapse_retrans(struct sock *sk, struct sk_buff *skb)
        sk_wmem_free_skb(sk, next_skb);
 }
 
+/* Check if coalescing SKBs is legal. */
 static int tcp_can_collapse(struct sock *sk, struct sk_buff *skb)
 {
        if (tcp_skb_pcount(skb) > 1)
@@ -1808,6 +1836,9 @@ static int tcp_can_collapse(struct sock *sk, struct sk_buff *skb)
        return 1;
 }
 
+/* Collapse packets in the retransmit queue to make to create
+ * less packets on the wire. This is only done on retransmission.
+ */
 static void tcp_retrans_try_collapse(struct sock *sk, struct sk_buff *to,
                                     int space)
 {
@@ -1957,6 +1988,9 @@ int tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb)
        return err;
 }
 
+/* Check if we forward retransmits are possible in the current
+ * window/congestion state.
+ */
 static int tcp_can_forward_retransmit(struct sock *sk)
 {
        const struct inet_connection_sock *icsk = inet_csk(sk);
@@ -2145,7 +2179,8 @@ void tcp_send_active_reset(struct sock *sk, gfp_t priority)
        TCP_INC_STATS(sock_net(sk), TCP_MIB_OUTRSTS);
 }
 
-/* WARNING: This routine must only be called when we have already sent
+/* Send a crossed SYN-ACK during socket establishment.
+ * WARNING: This routine must only be called when we have already sent
  * a SYN packet that crossed the incoming SYN that caused this routine
  * to get called. If this assumption fails then the initial rcv_wnd
  * and rcv_wscale values will not be correct.
@@ -2180,9 +2215,7 @@ int tcp_send_synack(struct sock *sk)
        return tcp_transmit_skb(sk, skb, 1, GFP_ATOMIC);
 }
 
-/*
- * Prepare a SYN-ACK.
- */
+/* Prepare a SYN-ACK. */
 struct sk_buff *tcp_make_synack(struct sock *sk, struct dst_entry *dst,
                                struct request_sock *req)
 {
@@ -2269,9 +2302,7 @@ struct sk_buff *tcp_make_synack(struct sock *sk, struct dst_entry *dst,
        return skb;
 }
 
-/*
- * Do all connect socket setups that can be done AF independent.
- */
+/* Do all connect socket setups that can be done AF independent. */
 static void tcp_connect_init(struct sock *sk)
 {
        struct dst_entry *dst = __sk_dst_get(sk);
@@ -2330,9 +2361,7 @@ static void tcp_connect_init(struct sock *sk)
        tcp_clear_retrans(tp);
 }
 
-/*
- * Build a SYN and send it off.
- */
+/* Build a SYN and send it off. */
 int tcp_connect(struct sock *sk)
 {
        struct tcp_sock *tp = tcp_sk(sk);
@@ -2493,6 +2522,7 @@ static int tcp_xmit_probe_skb(struct sock *sk, int urgent)
        return tcp_transmit_skb(sk, skb, 0, GFP_ATOMIC);
 }
 
+/* Initiate keepalive or window probe from timer. */
 int tcp_write_wakeup(struct sock *sk)
 {
        struct tcp_sock *tp = tcp_sk(sk);
index 80e3812..29ebb0d 100644 (file)
@@ -110,11 +110,12 @@ struct udp_table udp_table;
 EXPORT_SYMBOL(udp_table);
 
 int sysctl_udp_mem[3] __read_mostly;
-int sysctl_udp_rmem_min __read_mostly;
-int sysctl_udp_wmem_min __read_mostly;
-
 EXPORT_SYMBOL(sysctl_udp_mem);
+
+int sysctl_udp_rmem_min __read_mostly;
 EXPORT_SYMBOL(sysctl_udp_rmem_min);
+
+int sysctl_udp_wmem_min __read_mostly;
 EXPORT_SYMBOL(sysctl_udp_wmem_min);
 
 atomic_t udp_memory_allocated;
@@ -158,7 +159,7 @@ static int udp_lib_lport_inuse(struct net *net, __u16 num,
  */
 int udp_lib_get_port(struct sock *sk, unsigned short snum,
                       int (*saddr_comp)(const struct sock *sk1,
-                                        const struct sock *sk2 )    )
+                                        const struct sock *sk2))
 {
        struct udp_hslot *hslot;
        struct udp_table *udptable = sk->sk_prot->h.udp_table;
@@ -221,14 +222,15 @@ fail_unlock:
 fail:
        return error;
 }
+EXPORT_SYMBOL(udp_lib_get_port);
 
 static int ipv4_rcv_saddr_equal(const struct sock *sk1, const struct sock *sk2)
 {
        struct inet_sock *inet1 = inet_sk(sk1), *inet2 = inet_sk(sk2);
 
-       return  ( !ipv6_only_sock(sk2)  &&
-                 (!inet1->rcv_saddr || !inet2->rcv_saddr ||
-                  inet1->rcv_saddr == inet2->rcv_saddr      ));
+       return  (!ipv6_only_sock(sk2)  &&
+                (!inet1->rcv_saddr || !inet2->rcv_saddr ||
+                  inet1->rcv_saddr == inet2->rcv_saddr));
 }
 
 int udp_v4_get_port(struct sock *sk, unsigned short snum)
@@ -383,8 +385,8 @@ found:
 void __udp4_lib_err(struct sk_buff *skb, u32 info, struct udp_table *udptable)
 {
        struct inet_sock *inet;
-       struct iphdr *iph = (struct iphdr*)skb->data;
-       struct udphdr *uh = (struct udphdr*)(skb->data+(iph->ihl<<2));
+       struct iphdr *iph = (struct iphdr *)skb->data;
+       struct udphdr *uh = (struct udphdr *)(skb->data+(iph->ihl<<2));
        const int type = icmp_hdr(skb)->type;
        const int code = icmp_hdr(skb)->code;
        struct sock *sk;
@@ -439,7 +441,7 @@ void __udp4_lib_err(struct sk_buff *skb, u32 info, struct udp_table *udptable)
                if (!harderr || sk->sk_state != TCP_ESTABLISHED)
                        goto out;
        } else {
-               ip_icmp_error(sk, skb, err, uh->dest, info, (u8*)(uh+1));
+               ip_icmp_error(sk, skb, err, uh->dest, info, (u8 *)(uh+1));
        }
        sk->sk_err = err;
        sk->sk_error_report(sk);
@@ -474,7 +476,7 @@ EXPORT_SYMBOL(udp_flush_pending_frames);
  *             (checksum field must be zeroed out)
  */
 static void udp4_hwcsum_outgoing(struct sock *sk, struct sk_buff *skb,
-                                __be32 src, __be32 dst, int len      )
+                                __be32 src, __be32 dst, int len)
 {
        unsigned int offset;
        struct udphdr *uh = udp_hdr(skb);
@@ -545,7 +547,7 @@ static int udp_push_pending_frames(struct sock *sk)
 
        } else if (skb->ip_summed == CHECKSUM_PARTIAL) { /* UDP hardware csum */
 
-               udp4_hwcsum_outgoing(sk, skb, fl->fl4_src,fl->fl4_dst, up->len);
+               udp4_hwcsum_outgoing(sk, skb, fl->fl4_src, fl->fl4_dst, up->len);
                goto send;
 
        } else                                           /*   `normal' UDP    */
@@ -553,7 +555,7 @@ static int udp_push_pending_frames(struct sock *sk)
 
        /* add protocol-dependent pseudo-header */
        uh->check = csum_tcpudp_magic(fl->fl4_src, fl->fl4_dst, up->len,
-                                     sk->sk_protocol, csum             );
+                                     sk->sk_protocol, csum);
        if (uh->check == 0)
                uh->check = CSUM_MANGLED_0;
 
@@ -592,7 +594,7 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
         *      Check the flags.
         */
 
-       if (msg->msg_flags&MSG_OOB)     /* Mirror BSD error message compatibility */
+       if (msg->msg_flags & MSG_OOB) /* Mirror BSD error message compatibility */
                return -EOPNOTSUPP;
 
        ipc.opt = NULL;
@@ -619,7 +621,7 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
         *      Get and verify the address.
         */
        if (msg->msg_name) {
-               struct sockaddr_in * usin = (struct sockaddr_in*)msg->msg_name;
+               struct sockaddr_in * usin = (struct sockaddr_in *)msg->msg_name;
                if (msg->msg_namelen < sizeof(*usin))
                        return -EINVAL;
                if (usin->sin_family != AF_INET) {
@@ -684,7 +686,7 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
        }
 
        if (connected)
-               rt = (struct rtable*)sk_dst_check(sk, 0);
+               rt = (struct rtable *)sk_dst_check(sk, 0);
 
        if (rt == NULL) {
                struct flowi fl = { .oif = ipc.oif,
@@ -782,6 +784,7 @@ do_confirm:
        err = 0;
        goto out;
 }
+EXPORT_SYMBOL(udp_sendmsg);
 
 int udp_sendpage(struct sock *sk, struct page *page, int offset,
                 size_t size, int flags)
@@ -871,6 +874,7 @@ int udp_ioctl(struct sock *sk, int cmd, unsigned long arg)
 
        return 0;
 }
+EXPORT_SYMBOL(udp_ioctl);
 
 /*
  *     This should be easy, if there is something there we
@@ -892,7 +896,7 @@ int udp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
         *      Check any passed addresses
         */
        if (addr_len)
-               *addr_len=sizeof(*sin);
+               *addr_len = sizeof(*sin);
 
        if (flags & MSG_ERRQUEUE)
                return ip_recv_error(sk, msg, len);
@@ -923,9 +927,11 @@ try_again:
 
        if (skb_csum_unnecessary(skb))
                err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr),
-                                             msg->msg_iov, copied       );
+                                             msg->msg_iov, copied);
        else {
-               err = skb_copy_and_csum_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov);
+               err = skb_copy_and_csum_datagram_iovec(skb,
+                                                      sizeof(struct udphdr),
+                                                      msg->msg_iov);
 
                if (err == -EINVAL)
                        goto csum_copy_err;
@@ -941,8 +947,7 @@ try_again:
        sock_recv_timestamp(msg, sk, skb);
 
        /* Copy the address. */
-       if (sin)
-       {
+       if (sin) {
                sin->sin_family = AF_INET;
                sin->sin_port = udp_hdr(skb)->source;
                sin->sin_addr.s_addr = ip_hdr(skb)->saddr;
@@ -995,6 +1000,7 @@ int udp_disconnect(struct sock *sk, int flags)
        sk_dst_reset(sk);
        return 0;
 }
+EXPORT_SYMBOL(udp_disconnect);
 
 void udp_lib_unhash(struct sock *sk)
 {
@@ -1044,7 +1050,7 @@ drop:
  * Note that in the success and error cases, the skb is assumed to
  * have either been requeued or freed.
  */
-int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb)
+int udp_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
 {
        struct udp_sock *up = udp_sk(sk);
        int rc;
@@ -1214,7 +1220,7 @@ static inline int udp4_csum_init(struct sk_buff *skb, struct udphdr *uh,
        if (uh->check == 0) {
                skb->ip_summed = CHECKSUM_UNNECESSARY;
        } else if (skb->ip_summed == CHECKSUM_COMPLETE) {
-              if (!csum_tcpudp_magic(iph->saddr, iph->daddr, skb->len,
+               if (!csum_tcpudp_magic(iph->saddr, iph->daddr, skb->len,
                                      proto, skb->csum))
                        skb->ip_summed = CHECKSUM_UNNECESSARY;
        }
@@ -1355,7 +1361,7 @@ int udp_lib_setsockopt(struct sock *sk, int level, int optname,
        int err = 0;
        int is_udplite = IS_UDPLITE(sk);
 
-       if (optlen<sizeof(int))
+       if (optlen < sizeof(int))
                return -EINVAL;
 
        if (get_user(val, (int __user *)optval))
@@ -1426,6 +1432,7 @@ int udp_lib_setsockopt(struct sock *sk, int level, int optname,
 
        return err;
 }
+EXPORT_SYMBOL(udp_lib_setsockopt);
 
 int udp_setsockopt(struct sock *sk, int level, int optname,
                   char __user *optval, int optlen)
@@ -1453,7 +1460,7 @@ int udp_lib_getsockopt(struct sock *sk, int level, int optname,
        struct udp_sock *up = udp_sk(sk);
        int val, len;
 
-       if (get_user(len,optlen))
+       if (get_user(len, optlen))
                return -EFAULT;
 
        len = min_t(unsigned int, len, sizeof(int));
@@ -1486,10 +1493,11 @@ int udp_lib_getsockopt(struct sock *sk, int level, int optname,
 
        if (put_user(len, optlen))
                return -EFAULT;
-       if (copy_to_user(optval, &val,len))
+       if (copy_to_user(optval, &val, len))
                return -EFAULT;
        return 0;
 }
+EXPORT_SYMBOL(udp_lib_getsockopt);
 
 int udp_getsockopt(struct sock *sk, int level, int optname,
                   char __user *optval, int __user *optlen)
@@ -1528,9 +1536,9 @@ unsigned int udp_poll(struct file *file, struct socket *sock, poll_table *wait)
        int     is_lite = IS_UDPLITE(sk);
 
        /* Check for false positives due to checksum errors */
-       if ( (mask & POLLRDNORM) &&
-            !(file->f_flags & O_NONBLOCK) &&
-            !(sk->sk_shutdown & RCV_SHUTDOWN)){
+       if ((mask & POLLRDNORM) &&
+           !(file->f_flags & O_NONBLOCK) &&
+           !(sk->sk_shutdown & RCV_SHUTDOWN)) {
                struct sk_buff_head *rcvq = &sk->sk_receive_queue;
                struct sk_buff *skb;
 
@@ -1552,6 +1560,7 @@ unsigned int udp_poll(struct file *file, struct socket *sock, poll_table *wait)
        return mask;
 
 }
+EXPORT_SYMBOL(udp_poll);
 
 struct proto udp_prot = {
        .name              = "UDP",
@@ -1582,6 +1591,7 @@ struct proto udp_prot = {
        .compat_getsockopt = compat_udp_getsockopt,
 #endif
 };
+EXPORT_SYMBOL(udp_prot);
 
 /* ------------------------------------------------------------------------ */
 #ifdef CONFIG_PROC_FS
@@ -1703,11 +1713,13 @@ int udp_proc_register(struct net *net, struct udp_seq_afinfo *afinfo)
                rc = -ENOMEM;
        return rc;
 }
+EXPORT_SYMBOL(udp_proc_register);
 
 void udp_proc_unregister(struct net *net, struct udp_seq_afinfo *afinfo)
 {
        proc_net_remove(net, afinfo->name);
 }
+EXPORT_SYMBOL(udp_proc_unregister);
 
 /* ------------------------------------------------------------------------ */
 static void udp4_format_sock(struct sock *sp, struct seq_file *f,
@@ -1741,7 +1753,7 @@ int udp4_seq_show(struct seq_file *seq, void *v)
                int len;
 
                udp4_format_sock(v, seq, state->bucket, &len);
-               seq_printf(seq, "%*s\n", 127 - len ,"");
+               seq_printf(seq, "%*s\n", 127 - len"");
        }
        return 0;
 }
@@ -1816,16 +1828,64 @@ void __init udp_init(void)
        sysctl_udp_wmem_min = SK_MEM_QUANTUM;
 }
 
-EXPORT_SYMBOL(udp_disconnect);
-EXPORT_SYMBOL(udp_ioctl);
-EXPORT_SYMBOL(udp_prot);
-EXPORT_SYMBOL(udp_sendmsg);
-EXPORT_SYMBOL(udp_lib_getsockopt);
-EXPORT_SYMBOL(udp_lib_setsockopt);
-EXPORT_SYMBOL(udp_poll);
-EXPORT_SYMBOL(udp_lib_get_port);
+int udp4_ufo_send_check(struct sk_buff *skb)
+{
+       const struct iphdr *iph;
+       struct udphdr *uh;
+
+       if (!pskb_may_pull(skb, sizeof(*uh)))
+               return -EINVAL;
+
+       iph = ip_hdr(skb);
+       uh = udp_hdr(skb);
+
+       uh->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr, skb->len,
+                                      IPPROTO_UDP, 0);
+       skb->csum_start = skb_transport_header(skb) - skb->head;
+       skb->csum_offset = offsetof(struct udphdr, check);
+       skb->ip_summed = CHECKSUM_PARTIAL;
+       return 0;
+}
+
+struct sk_buff *udp4_ufo_fragment(struct sk_buff *skb, int features)
+{
+       struct sk_buff *segs = ERR_PTR(-EINVAL);
+       unsigned int mss;
+       int offset;
+       __wsum csum;
+
+       mss = skb_shinfo(skb)->gso_size;
+       if (unlikely(skb->len <= mss))
+               goto out;
+
+       if (skb_gso_ok(skb, features | NETIF_F_GSO_ROBUST)) {
+               /* Packet is from an untrusted source, reset gso_segs. */
+               int type = skb_shinfo(skb)->gso_type;
+
+               if (unlikely(type & ~(SKB_GSO_UDP | SKB_GSO_DODGY) ||
+                            !(type & (SKB_GSO_UDP))))
+                       goto out;
+
+               skb_shinfo(skb)->gso_segs = DIV_ROUND_UP(skb->len, mss);
+
+               segs = NULL;
+               goto out;
+       }
+
+       /* Do software UFO. Complete and fill in the UDP checksum as HW cannot
+        * do checksum of UDP packets sent as multiple IP fragments.
+        */
+       offset = skb->csum_start - skb_headroom(skb);
+       csum = skb_checksum(skb, offset, skb->len - offset, 0);
+       offset += skb->csum_offset;
+       *(__sum16 *)(skb->data + offset) = csum_fold(csum);
+       skb->ip_summed = CHECKSUM_NONE;
+
+       /* Fragment the skb. IP headers of the fragments are updated in
+        * inet_gso_segment()
+        */
+       segs = skb_segment(skb, features);
+out:
+       return segs;
+}
 
-#ifdef CONFIG_PROC_FS
-EXPORT_SYMBOL(udp_proc_register);
-EXPORT_SYMBOL(udp_proc_unregister);
-#endif
index caa0278..bf85d5f 100644 (file)
@@ -772,6 +772,11 @@ static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb, int features)
        struct sk_buff *segs = ERR_PTR(-EINVAL);
        struct ipv6hdr *ipv6h;
        struct inet6_protocol *ops;
+       int proto;
+       struct frag_hdr *fptr;
+       unsigned int unfrag_ip6hlen;
+       u8 *prevhdr;
+       int offset = 0;
 
        if (!(features & NETIF_F_V6_CSUM))
                features &= ~NETIF_F_SG;
@@ -791,10 +796,9 @@ static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb, int features)
        __skb_pull(skb, sizeof(*ipv6h));
        segs = ERR_PTR(-EPROTONOSUPPORT);
 
+       proto = ipv6_gso_pull_exthdrs(skb, ipv6h->nexthdr);
        rcu_read_lock();
-       ops = rcu_dereference(inet6_protos[
-               ipv6_gso_pull_exthdrs(skb, ipv6h->nexthdr)]);
-
+       ops = rcu_dereference(inet6_protos[proto]);
        if (likely(ops && ops->gso_segment)) {
                skb_reset_transport_header(skb);
                segs = ops->gso_segment(skb, features);
@@ -808,6 +812,16 @@ static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb, int features)
                ipv6h = ipv6_hdr(skb);
                ipv6h->payload_len = htons(skb->len - skb->mac_len -
                                           sizeof(*ipv6h));
+               if (proto == IPPROTO_UDP) {
+                       unfrag_ip6hlen = ip6_find_1stfragopt(skb, &prevhdr);
+                       fptr = (struct frag_hdr *)(skb_network_header(skb) +
+                               unfrag_ip6hlen);
+                       fptr->frag_off = htons(offset);
+                       if (skb->next != NULL)
+                               fptr->frag_off |= htons(IP6_MF);
+                       offset += (ntohs(ipv6h->payload_len) -
+                                  sizeof(struct frag_hdr));
+               }
        }
 
 out:
index 6d6a427..2d9cbaa 100644 (file)
@@ -63,7 +63,7 @@ int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt
 
        if (skb->pkt_type == PACKET_OTHERHOST) {
                kfree_skb(skb);
-               return 0;
+               return NET_RX_DROP;
        }
 
        rcu_read_lock();
@@ -133,7 +133,7 @@ int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt
                if (ipv6_parse_hopopts(skb) < 0) {
                        IP6_INC_STATS_BH(net, idev, IPSTATS_MIB_INHDRERRORS);
                        rcu_read_unlock();
-                       return 0;
+                       return NET_RX_DROP;
                }
        }
 
@@ -149,7 +149,7 @@ err:
 drop:
        rcu_read_unlock();
        kfree_skb(skb);
-       return 0;
+       return NET_RX_DROP;
 }
 
 /*
index 87f8419..93beee9 100644 (file)
 
 static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *));
 
-static __inline__ void ipv6_select_ident(struct sk_buff *skb, struct frag_hdr *fhdr)
-{
-       static u32 ipv6_fragmentation_id = 1;
-       static DEFINE_SPINLOCK(ip6_id_lock);
-
-       spin_lock_bh(&ip6_id_lock);
-       fhdr->identification = htonl(ipv6_fragmentation_id);
-       if (++ipv6_fragmentation_id == 0)
-               ipv6_fragmentation_id = 1;
-       spin_unlock_bh(&ip6_id_lock);
-}
-
 int __ip6_local_out(struct sk_buff *skb)
 {
        int len;
@@ -706,7 +694,7 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
                skb_reset_network_header(skb);
                memcpy(skb_network_header(skb), tmp_hdr, hlen);
 
-               ipv6_select_ident(skb, fh);
+               ipv6_select_ident(fh);
                fh->nexthdr = nexthdr;
                fh->reserved = 0;
                fh->frag_off = htons(IP6_MF);
@@ -844,7 +832,7 @@ slow_path:
                fh->nexthdr = nexthdr;
                fh->reserved = 0;
                if (!frag_id) {
-                       ipv6_select_ident(skb, fh);
+                       ipv6_select_ident(fh);
                        frag_id = fh->identification;
                } else
                        fh->identification = frag_id;
@@ -1087,11 +1075,13 @@ static inline int ip6_ufo_append_data(struct sock *sk,
        if (!err) {
                struct frag_hdr fhdr;
 
-               /* specify the length of each IP datagram fragment*/
-               skb_shinfo(skb)->gso_size = mtu - fragheaderlen -
-                                           sizeof(struct frag_hdr);
+               /* Specify the length of each IPv6 datagram fragment.
+                * It has to be a multiple of 8.
+                */
+               skb_shinfo(skb)->gso_size = (mtu - fragheaderlen -
+                                            sizeof(struct frag_hdr)) & ~7;
                skb_shinfo(skb)->gso_type = SKB_GSO_UDP;
-               ipv6_select_ident(skb, &fhdr);
+               ipv6_select_ident(&fhdr);
                skb_shinfo(skb)->ip6_frag_id = fhdr.identification;
                __skb_queue_tail(&sk->sk_write_queue, skb);
 
index 51f410e..a1d6045 100644 (file)
@@ -1063,14 +1063,14 @@ ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
                goto tx_err;
 
        t->recursion--;
-       return 0;
+       return NETDEV_TX_OK;
 
 tx_err:
        stats->tx_errors++;
        stats->tx_dropped++;
        kfree_skb(skb);
        t->recursion--;
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 static void ip6_tnl_set_cap(struct ip6_tnl *t)
index c769f15..07ded50 100644 (file)
@@ -427,7 +427,7 @@ static int reg_vif_xmit(struct sk_buff *skb, struct net_device *dev)
                           MRT6MSG_WHOLEPKT);
        read_unlock(&mrt_lock);
        kfree_skb(skb);
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 static const struct net_device_ops reg_vif_netdev_ops = {
index 4b264ed..71c3dac 100644 (file)
@@ -2107,7 +2107,6 @@ static int ip6_mc_add_src(struct inet6_dev *idev, struct in6_addr *pmca,
                for (j=0; j<i; j++)
                        (void) ip6_mc_del1_src(pmc, sfmode, &psfsrc[i]);
        } else if (isexclude != (pmc->mca_sfcount[MCAST_EXCLUDE] != 0)) {
-               struct inet6_dev *idev = pmc->idev;
                struct ip6_sf_list *psf;
 
                /* filter mode change */
index 98b7327..d335a30 100644 (file)
@@ -753,7 +753,7 @@ static int ipip6_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
                        stats->tx_dropped++;
                        dev_kfree_skb(skb);
                        tunnel->recursion--;
-                       return 0;
+                       return NETDEV_TX_OK;
                }
                if (skb->sk)
                        skb_set_owner_w(new_skb, skb->sk);
@@ -794,7 +794,7 @@ static int ipip6_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
 
        IPTUNNEL_XMIT();
        tunnel->recursion--;
-       return 0;
+       return NETDEV_TX_OK;
 
 tx_error_icmp:
        dst_link_failure(skb);
@@ -802,7 +802,7 @@ tx_error:
        stats->tx_errors++;
        dev_kfree_skb(skb);
        tunnel->recursion--;
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 static void ipip6_tunnel_bind_dev(struct net_device *dev)
index 33b59bd..d79fa67 100644 (file)
@@ -638,6 +638,47 @@ static void udp_v6_flush_pending_frames(struct sock *sk)
        }
 }
 
+/**
+ *     udp6_hwcsum_outgoing  -  handle outgoing HW checksumming
+ *     @sk:    socket we are sending on
+ *     @skb:   sk_buff containing the filled-in UDP header
+ *             (checksum field must be zeroed out)
+ */
+static void udp6_hwcsum_outgoing(struct sock *sk, struct sk_buff *skb,
+                                const struct in6_addr *saddr,
+                                const struct in6_addr *daddr, int len)
+{
+       unsigned int offset;
+       struct udphdr *uh = udp_hdr(skb);
+       __wsum csum = 0;
+
+       if (skb_queue_len(&sk->sk_write_queue) == 1) {
+               /* Only one fragment on the socket.  */
+               skb->csum_start = skb_transport_header(skb) - skb->head;
+               skb->csum_offset = offsetof(struct udphdr, check);
+               uh->check = ~csum_ipv6_magic(saddr, daddr, len, IPPROTO_UDP, 0);
+       } else {
+               /*
+                * HW-checksum won't work as there are two or more
+                * fragments on the socket so that all csums of sk_buffs
+                * should be together
+                */
+               offset = skb_transport_offset(skb);
+               skb->csum = skb_checksum(skb, offset, skb->len - offset, 0);
+
+               skb->ip_summed = CHECKSUM_NONE;
+
+               skb_queue_walk(&sk->sk_write_queue, skb) {
+                       csum = csum_add(csum, skb->csum);
+               }
+
+               uh->check = csum_ipv6_magic(saddr, daddr, len, IPPROTO_UDP,
+                                           csum);
+               if (uh->check == 0)
+                       uh->check = CSUM_MANGLED_0;
+       }
+}
+
 /*
  *     Sending
  */
@@ -668,7 +709,11 @@ static int udp_v6_push_pending_frames(struct sock *sk)
 
        if (is_udplite)
                csum = udplite_csum_outgoing(sk, skb);
-        else
+       else if (skb->ip_summed == CHECKSUM_PARTIAL) { /* UDP hardware csum */
+               udp6_hwcsum_outgoing(sk, skb, &fl->fl6_src, &fl->fl6_dst,
+                                    up->len);
+               goto send;
+       } else
                csum = udp_csum_outgoing(sk, skb);
 
        /* add protocol-dependent pseudo-header */
@@ -677,6 +722,7 @@ static int udp_v6_push_pending_frames(struct sock *sk)
        if (uh->check == 0)
                uh->check = CSUM_MANGLED_0;
 
+send:
        err = ip6_push_pending_frames(sk);
 out:
        up->len = 0;
@@ -1032,9 +1078,102 @@ int compat_udpv6_getsockopt(struct sock *sk, int level, int optname,
 }
 #endif
 
+static int udp6_ufo_send_check(struct sk_buff *skb)
+{
+       struct ipv6hdr *ipv6h;
+       struct udphdr *uh;
+
+       if (!pskb_may_pull(skb, sizeof(*uh)))
+               return -EINVAL;
+
+       ipv6h = ipv6_hdr(skb);
+       uh = udp_hdr(skb);
+
+       uh->check = ~csum_ipv6_magic(&ipv6h->saddr, &ipv6h->daddr, skb->len,
+                                    IPPROTO_UDP, 0);
+       skb->csum_start = skb_transport_header(skb) - skb->head;
+       skb->csum_offset = offsetof(struct udphdr, check);
+       skb->ip_summed = CHECKSUM_PARTIAL;
+       return 0;
+}
+
+static struct sk_buff *udp6_ufo_fragment(struct sk_buff *skb, int features)
+{
+       struct sk_buff *segs = ERR_PTR(-EINVAL);
+       unsigned int mss;
+       unsigned int unfrag_ip6hlen, unfrag_len;
+       struct frag_hdr *fptr;
+       u8 *mac_start, *prevhdr;
+       u8 nexthdr;
+       u8 frag_hdr_sz = sizeof(struct frag_hdr);
+       int offset;
+       __wsum csum;
+
+       mss = skb_shinfo(skb)->gso_size;
+       if (unlikely(skb->len <= mss))
+               goto out;
+
+       if (skb_gso_ok(skb, features | NETIF_F_GSO_ROBUST)) {
+               /* Packet is from an untrusted source, reset gso_segs. */
+               int type = skb_shinfo(skb)->gso_type;
+
+               if (unlikely(type & ~(SKB_GSO_UDP | SKB_GSO_DODGY) ||
+                            !(type & (SKB_GSO_UDP))))
+                       goto out;
+
+               skb_shinfo(skb)->gso_segs = DIV_ROUND_UP(skb->len, mss);
+
+               segs = NULL;
+               goto out;
+       }
+
+       /* Do software UFO. Complete and fill in the UDP checksum as HW cannot
+        * do checksum of UDP packets sent as multiple IP fragments.
+        */
+       offset = skb->csum_start - skb_headroom(skb);
+       csum = skb_checksum(skb, offset, skb->len- offset, 0);
+       offset += skb->csum_offset;
+       *(__sum16 *)(skb->data + offset) = csum_fold(csum);
+       skb->ip_summed = CHECKSUM_NONE;
+
+       /* Check if there is enough headroom to insert fragment header. */
+       if ((skb_headroom(skb) < frag_hdr_sz) &&
+           pskb_expand_head(skb, frag_hdr_sz, 0, GFP_ATOMIC))
+               goto out;
+
+       /* Find the unfragmentable header and shift it left by frag_hdr_sz
+        * bytes to insert fragment header.
+        */
+       unfrag_ip6hlen = ip6_find_1stfragopt(skb, &prevhdr);
+       nexthdr = *prevhdr;
+       *prevhdr = NEXTHDR_FRAGMENT;
+       unfrag_len = skb_network_header(skb) - skb_mac_header(skb) +
+                    unfrag_ip6hlen;
+       mac_start = skb_mac_header(skb);
+       memmove(mac_start-frag_hdr_sz, mac_start, unfrag_len);
+
+       skb->mac_header -= frag_hdr_sz;
+       skb->network_header -= frag_hdr_sz;
+
+       fptr = (struct frag_hdr *)(skb_network_header(skb) + unfrag_ip6hlen);
+       fptr->nexthdr = nexthdr;
+       fptr->reserved = 0;
+       ipv6_select_ident(fptr);
+
+       /* Fragment the skb. ipv6 header and the remaining fields of the
+        * fragment header are updated in ipv6_gso_segment()
+        */
+       segs = skb_segment(skb, features);
+
+out:
+       return segs;
+}
+
 static struct inet6_protocol udpv6_protocol = {
        .handler        =       udpv6_rcv,
        .err_handler    =       udpv6_err,
+       .gso_send_check =       udp6_ufo_send_check,
+       .gso_segment    =       udp6_ufo_fragment,
        .flags          =       INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL,
 };
 
index 724bcf9..64230cf 100644 (file)
@@ -177,7 +177,7 @@ static int irlan_eth_xmit(struct sk_buff *skb, struct net_device *dev)
 
                /* Did the realloc succeed? */
                if (new_skb == NULL)
-                       return 0;
+                       return NETDEV_TX_OK;
 
                /* Use the new skb instead */
                skb = new_skb;
@@ -209,7 +209,7 @@ static int irlan_eth_xmit(struct sk_buff *skb, struct net_device *dev)
                self->stats.tx_bytes += skb->len;
        }
 
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 /*
index 8dd7ed7..476b307 100644 (file)
@@ -115,7 +115,7 @@ static int irda_nl_get_mode(struct sk_buff *skb, struct genl_info *info)
 
        genlmsg_end(msg, hdr);
 
-       return genlmsg_unicast(msg, info->snd_pid);
+       return genlmsg_reply(msg, info);
 
  err_out:
        nlmsg_free(msg);
index 2ba1bc4..bda96d1 100644 (file)
@@ -407,7 +407,7 @@ int lapb_data_indication(struct lapb_cb *lapb, struct sk_buff *skb)
                return lapb->callbacks.data_indication(lapb->dev, skb);
 
        kfree_skb(skb);
-       return NET_RX_CN_HIGH; /* For now; must be != NET_RX_DROP */
+       return NET_RX_SUCCESS; /* For now; must be != NET_RX_DROP */
 }
 
 int lapb_data_transmit(struct lapb_cb *lapb, struct sk_buff *skb)
index 7836ee9..182c9c5 100644 (file)
@@ -14,22 +14,6 @@ config MAC80211
 comment "CFG80211 needs to be enabled for MAC80211"
        depends on CFG80211=n
 
-config MAC80211_DEFAULT_PS
-       bool "enable powersave by default"
-       depends on MAC80211
-       default y
-       help
-         This option enables powersave mode by default.
-
-         If this causes your applications to misbehave you should fix your
-         applications instead -- they need to register their network
-         latency requirement, see Documentation/power/pm_qos_interface.txt.
-
-config MAC80211_DEFAULT_PS_VALUE
-       int
-       default 1 if MAC80211_DEFAULT_PS
-       default 0
-
 menu "Rate control algorithm selection"
        depends on MAC80211 != n
 
index 3f47276..36f8f24 100644 (file)
@@ -74,19 +74,14 @@ static int ieee80211_del_iface(struct wiphy *wiphy, int ifindex)
        return 0;
 }
 
-static int ieee80211_change_iface(struct wiphy *wiphy, int ifindex,
+static int ieee80211_change_iface(struct wiphy *wiphy,
+                                 struct net_device *dev,
                                  enum nl80211_iftype type, u32 *flags,
                                  struct vif_params *params)
 {
-       struct net_device *dev;
        struct ieee80211_sub_if_data *sdata;
        int ret;
 
-       /* we're under RTNL */
-       dev = __dev_get_by_index(&init_net, ifindex);
-       if (!dev)
-               return -ENODEV;
-
        if (!nl80211_type_check(type))
                return -EINVAL;
 
@@ -1177,123 +1172,29 @@ static int ieee80211_scan(struct wiphy *wiphy,
 static int ieee80211_auth(struct wiphy *wiphy, struct net_device *dev,
                          struct cfg80211_auth_request *req)
 {
-       struct ieee80211_sub_if_data *sdata;
-
-       sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-
-       switch (req->auth_type) {
-       case NL80211_AUTHTYPE_OPEN_SYSTEM:
-               sdata->u.mgd.auth_algs = IEEE80211_AUTH_ALG_OPEN;
-               break;
-       case NL80211_AUTHTYPE_SHARED_KEY:
-               sdata->u.mgd.auth_algs = IEEE80211_AUTH_ALG_SHARED_KEY;
-               break;
-       case NL80211_AUTHTYPE_FT:
-               sdata->u.mgd.auth_algs = IEEE80211_AUTH_ALG_FT;
-               break;
-       case NL80211_AUTHTYPE_NETWORK_EAP:
-               sdata->u.mgd.auth_algs = IEEE80211_AUTH_ALG_LEAP;
-               break;
-       default:
-               return -EOPNOTSUPP;
-       }
-
-       memcpy(sdata->u.mgd.bssid, req->peer_addr, ETH_ALEN);
-       sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_BSSID_SEL;
-       sdata->u.mgd.flags |= IEEE80211_STA_BSSID_SET;
-
-       /* TODO: req->chan */
-       sdata->u.mgd.flags |= IEEE80211_STA_AUTO_CHANNEL_SEL;
-
-       if (req->ssid) {
-               sdata->u.mgd.flags |= IEEE80211_STA_SSID_SET;
-               memcpy(sdata->u.mgd.ssid, req->ssid, req->ssid_len);
-               sdata->u.mgd.ssid_len = req->ssid_len;
-               sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_SSID_SEL;
-       }
-
-       kfree(sdata->u.mgd.sme_auth_ie);
-       sdata->u.mgd.sme_auth_ie = NULL;
-       sdata->u.mgd.sme_auth_ie_len = 0;
-       if (req->ie) {
-               sdata->u.mgd.sme_auth_ie = kmalloc(req->ie_len, GFP_KERNEL);
-               if (sdata->u.mgd.sme_auth_ie == NULL)
-                       return -ENOMEM;
-               memcpy(sdata->u.mgd.sme_auth_ie, req->ie, req->ie_len);
-               sdata->u.mgd.sme_auth_ie_len = req->ie_len;
-       }
-
-       sdata->u.mgd.flags |= IEEE80211_STA_EXT_SME;
-       sdata->u.mgd.state = IEEE80211_STA_MLME_DIRECT_PROBE;
-       ieee80211_sta_req_auth(sdata);
-       return 0;
+       return ieee80211_mgd_auth(IEEE80211_DEV_TO_SUB_IF(dev), req);
 }
 
 static int ieee80211_assoc(struct wiphy *wiphy, struct net_device *dev,
                           struct cfg80211_assoc_request *req)
 {
-       struct ieee80211_sub_if_data *sdata;
-       int ret;
-
-       sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-
-       if (memcmp(sdata->u.mgd.bssid, req->peer_addr, ETH_ALEN) != 0 ||
-           !(sdata->u.mgd.flags & IEEE80211_STA_AUTHENTICATED))
-               return -ENOLINK; /* not authenticated */
-
-       sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_BSSID_SEL;
-       sdata->u.mgd.flags |= IEEE80211_STA_BSSID_SET;
-
-       /* TODO: req->chan */
-       sdata->u.mgd.flags |= IEEE80211_STA_AUTO_CHANNEL_SEL;
-
-       if (req->ssid) {
-               sdata->u.mgd.flags |= IEEE80211_STA_SSID_SET;
-               memcpy(sdata->u.mgd.ssid, req->ssid, req->ssid_len);
-               sdata->u.mgd.ssid_len = req->ssid_len;
-               sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_SSID_SEL;
-       } else
-               sdata->u.mgd.flags |= IEEE80211_STA_AUTO_SSID_SEL;
-
-       ret = ieee80211_sta_set_extra_ie(sdata, req->ie, req->ie_len);
-       if (ret && ret != -EALREADY)
-               return ret;
-
-       if (req->use_mfp) {
-               sdata->u.mgd.mfp = IEEE80211_MFP_REQUIRED;
-               sdata->u.mgd.flags |= IEEE80211_STA_MFP_ENABLED;
-       } else {
-               sdata->u.mgd.mfp = IEEE80211_MFP_DISABLED;
-               sdata->u.mgd.flags &= ~IEEE80211_STA_MFP_ENABLED;
-       }
-
-       if (req->control_port)
-               sdata->u.mgd.flags |= IEEE80211_STA_CONTROL_PORT;
-       else
-               sdata->u.mgd.flags &= ~IEEE80211_STA_CONTROL_PORT;
-
-       sdata->u.mgd.flags |= IEEE80211_STA_EXT_SME;
-       sdata->u.mgd.state = IEEE80211_STA_MLME_ASSOCIATE;
-       ieee80211_sta_req_auth(sdata);
-       return 0;
+       return ieee80211_mgd_assoc(IEEE80211_DEV_TO_SUB_IF(dev), req);
 }
 
 static int ieee80211_deauth(struct wiphy *wiphy, struct net_device *dev,
-                           struct cfg80211_deauth_request *req)
+                           struct cfg80211_deauth_request *req,
+                           void *cookie)
 {
-       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-
-       /* TODO: req->ie, req->peer_addr */
-       return ieee80211_sta_deauthenticate(sdata, req->reason_code);
+       return ieee80211_mgd_deauth(IEEE80211_DEV_TO_SUB_IF(dev),
+                                   req, cookie);
 }
 
 static int ieee80211_disassoc(struct wiphy *wiphy, struct net_device *dev,
-                             struct cfg80211_disassoc_request *req)
+                             struct cfg80211_disassoc_request *req,
+                             void *cookie)
 {
-       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-
-       /* TODO: req->ie, req->peer_addr */
-       return ieee80211_sta_disassociate(sdata, req->reason_code);
+       return ieee80211_mgd_disassoc(IEEE80211_DEV_TO_SUB_IF(dev),
+                                     req, cookie);
 }
 
 static int ieee80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
@@ -1374,6 +1275,16 @@ static int ieee80211_get_tx_power(struct wiphy *wiphy, int *dbm)
        return 0;
 }
 
+static int ieee80211_set_wds_peer(struct wiphy *wiphy, struct net_device *dev,
+                                 u8 *addr)
+{
+       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+       memcpy(&sdata->u.wds.remote_addr, addr, ETH_ALEN);
+
+       return 0;
+}
+
 static void ieee80211_rfkill_poll(struct wiphy *wiphy)
 {
        struct ieee80211_local *local = wiphy_priv(wiphy);
@@ -1381,6 +1292,85 @@ static void ieee80211_rfkill_poll(struct wiphy *wiphy)
        drv_rfkill_poll(local);
 }
 
+#ifdef CONFIG_NL80211_TESTMODE
+int ieee80211_testmode_cmd(struct wiphy *wiphy, void *data, int len)
+{
+       struct ieee80211_local *local = wiphy_priv(wiphy);
+
+       if (!local->ops->testmode_cmd)
+               return -EOPNOTSUPP;
+
+       return local->ops->testmode_cmd(&local->hw, data, len);
+}
+#endif
+
+static int ieee80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev,
+                                   bool enabled, int timeout)
+{
+       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+       struct ieee80211_conf *conf = &local->hw.conf;
+
+       if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_PS))
+               return -EOPNOTSUPP;
+
+       if (enabled == sdata->u.mgd.powersave &&
+           timeout == conf->dynamic_ps_timeout)
+               return 0;
+
+       sdata->u.mgd.powersave = enabled;
+       conf->dynamic_ps_timeout = timeout;
+
+       if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS)
+               ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
+
+       ieee80211_recalc_ps(local, -1);
+
+       return 0;
+}
+
+static int ieee80211_set_bitrate_mask(struct wiphy *wiphy,
+                                     struct net_device *dev,
+                                     const u8 *addr,
+                                     const struct cfg80211_bitrate_mask *mask)
+{
+       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+       int i, err = -EINVAL;
+       u32 target_rate;
+       struct ieee80211_supported_band *sband;
+
+       sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+
+       /* target_rate = -1, rate->fixed = 0 means auto only, so use all rates
+        * target_rate = X, rate->fixed = 1 means only rate X
+        * target_rate = X, rate->fixed = 0 means all rates <= X */
+       sdata->max_ratectrl_rateidx = -1;
+       sdata->force_unicast_rateidx = -1;
+
+       if (mask->fixed)
+               target_rate = mask->fixed / 100;
+       else if (mask->maxrate)
+               target_rate = mask->maxrate / 100;
+       else
+               return 0;
+
+       for (i=0; i< sband->n_bitrates; i++) {
+               struct ieee80211_rate *brate = &sband->bitrates[i];
+               int this_rate = brate->bitrate;
+
+               if (target_rate == this_rate) {
+                       sdata->max_ratectrl_rateidx = i;
+                       if (mask->fixed)
+                               sdata->force_unicast_rateidx = i;
+                       err = 0;
+                       break;
+               }
+       }
+
+       return err;
+}
+
 struct cfg80211_ops mac80211_config_ops = {
        .add_virtual_intf = ieee80211_add_iface,
        .del_virtual_intf = ieee80211_del_iface,
@@ -1422,5 +1412,9 @@ struct cfg80211_ops mac80211_config_ops = {
        .set_wiphy_params = ieee80211_set_wiphy_params,
        .set_tx_power = ieee80211_set_tx_power,
        .get_tx_power = ieee80211_get_tx_power,
+       .set_wds_peer = ieee80211_set_wds_peer,
        .rfkill_poll = ieee80211_rfkill_poll,
+       CFG80211_TESTMODE_CMD(ieee80211_testmode_cmd)
+       .set_power_mgmt = ieee80211_set_power_mgmt,
+       .set_bitrate_mask = ieee80211_set_bitrate_mask,
 };
index e342032..e9ec6ca 100644 (file)
@@ -95,33 +95,9 @@ IEEE80211_IF_FILE(force_unicast_rateidx, force_unicast_rateidx, DEC);
 IEEE80211_IF_FILE(max_ratectrl_rateidx, max_ratectrl_rateidx, 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.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);
 
 /* AP attributes */
 IEEE80211_IF_FILE(num_sta_ps, u.ap.num_sta_ps, ATOMIC);
@@ -184,20 +160,9 @@ static void add_sta_files(struct ieee80211_sub_if_data *sdata)
        DEBUGFS_ADD(force_unicast_rateidx, sta);
        DEBUGFS_ADD(max_ratectrl_rateidx, sta);
 
-       DEBUGFS_ADD(state, sta);
        DEBUGFS_ADD(bssid, sta);
-       DEBUGFS_ADD(prev_bssid, sta);
-       DEBUGFS_ADD(ssid_len, sta);
        DEBUGFS_ADD(aid, sta);
-       DEBUGFS_ADD(ap_capab, sta);
        DEBUGFS_ADD(capab, sta);
-       DEBUGFS_ADD(extra_ie_len, sta);
-       DEBUGFS_ADD(auth_tries, sta);
-       DEBUGFS_ADD(assoc_tries, sta);
-       DEBUGFS_ADD(auth_algs, sta);
-       DEBUGFS_ADD(auth_alg, sta);
-       DEBUGFS_ADD(auth_transaction, sta);
-       DEBUGFS_ADD(flags, sta);
 }
 
 static void add_ap_files(struct ieee80211_sub_if_data *sdata)
@@ -317,20 +282,9 @@ static void del_sta_files(struct ieee80211_sub_if_data *sdata)
        DEBUGFS_DEL(force_unicast_rateidx, sta);
        DEBUGFS_DEL(max_ratectrl_rateidx, sta);
 
-       DEBUGFS_DEL(state, sta);
        DEBUGFS_DEL(bssid, sta);
-       DEBUGFS_DEL(prev_bssid, sta);
-       DEBUGFS_DEL(ssid_len, sta);
        DEBUGFS_DEL(aid, sta);
-       DEBUGFS_DEL(ap_capab, sta);
        DEBUGFS_DEL(capab, sta);
-       DEBUGFS_DEL(extra_ie_len, sta);
-       DEBUGFS_DEL(auth_tries, sta);
-       DEBUGFS_DEL(assoc_tries, sta);
-       DEBUGFS_DEL(auth_algs, sta);
-       DEBUGFS_DEL(auth_alg, sta);
-       DEBUGFS_DEL(auth_transaction, sta);
-       DEBUGFS_DEL(flags, sta);
 }
 
 static void del_ap_files(struct ieee80211_sub_if_data *sdata)
index 90230c7..33a2e89 100644 (file)
@@ -120,45 +120,38 @@ STA_OPS(last_seq_ctrl);
 static ssize_t sta_agg_status_read(struct file *file, char __user *userbuf,
                                        size_t count, loff_t *ppos)
 {
-       char buf[768], *p = buf;
+       char buf[30 + STA_TID_NUM * 70], *p = buf;
        int i;
        struct sta_info *sta = file->private_data;
-       p += scnprintf(p, sizeof(buf)+buf-p, "Agg state for STA is:\n");
-       p += scnprintf(p, sizeof(buf)+buf-p, " STA next dialog_token is %d \n "
-                       "TIDs info is: \n TID :",
-                       (sta->ampdu_mlme.dialog_token_allocator + 1));
-       for (i = 0; i < STA_TID_NUM; i++)
-               p += scnprintf(p, sizeof(buf)+buf-p, "%5d", i);
-
-       p += scnprintf(p, sizeof(buf)+buf-p, "\n RX  :");
-       for (i = 0; i < STA_TID_NUM; i++)
-               p += scnprintf(p, sizeof(buf)+buf-p, "%5d",
-                       sta->ampdu_mlme.tid_state_rx[i]);
-
-       p += scnprintf(p, sizeof(buf)+buf-p, "\n DTKN:");
-       for (i = 0; i < STA_TID_NUM; i++)
-               p += scnprintf(p, sizeof(buf)+buf-p, "%5d",
-                       sta->ampdu_mlme.tid_state_rx[i] ?
-                       sta->ampdu_mlme.tid_rx[i]->dialog_token : 0);
-
-       p += scnprintf(p, sizeof(buf)+buf-p, "\n TX  :");
-       for (i = 0; i < STA_TID_NUM; i++)
-               p += scnprintf(p, sizeof(buf)+buf-p, "%5d",
-                       sta->ampdu_mlme.tid_state_tx[i]);
-
-       p += scnprintf(p, sizeof(buf)+buf-p, "\n DTKN:");
-       for (i = 0; i < STA_TID_NUM; i++)
-               p += scnprintf(p, sizeof(buf)+buf-p, "%5d",
-                       sta->ampdu_mlme.tid_state_tx[i] ?
-                       sta->ampdu_mlme.tid_tx[i]->dialog_token : 0);
-
-       p += scnprintf(p, sizeof(buf)+buf-p, "\n SSN :");
-       for (i = 0; i < STA_TID_NUM; i++)
-               p += scnprintf(p, sizeof(buf)+buf-p, "%5d",
-                       sta->ampdu_mlme.tid_state_tx[i] ?
-                       sta->ampdu_mlme.tid_tx[i]->ssn : 0);
 
-       p += scnprintf(p, sizeof(buf)+buf-p, "\n");
+       spin_lock_bh(&sta->lock);
+       p += scnprintf(p, sizeof(buf)+buf-p, "next dialog_token is %#02x\n",
+                       sta->ampdu_mlme.dialog_token_allocator + 1);
+       for (i = 0; i < STA_TID_NUM; i++) {
+               p += scnprintf(p, sizeof(buf)+buf-p, "TID %02d:", i);
+               p += scnprintf(p, sizeof(buf)+buf-p, " RX=%x",
+                               sta->ampdu_mlme.tid_state_rx[i]);
+               p += scnprintf(p, sizeof(buf)+buf-p, "/DTKN=%#.2x",
+                               sta->ampdu_mlme.tid_state_rx[i] ?
+                               sta->ampdu_mlme.tid_rx[i]->dialog_token : 0);
+               p += scnprintf(p, sizeof(buf)+buf-p, "/SSN=%#.3x",
+                               sta->ampdu_mlme.tid_state_rx[i] ?
+                               sta->ampdu_mlme.tid_rx[i]->ssn : 0);
+
+               p += scnprintf(p, sizeof(buf)+buf-p, " TX=%x",
+                               sta->ampdu_mlme.tid_state_tx[i]);
+               p += scnprintf(p, sizeof(buf)+buf-p, "/DTKN=%#.2x",
+                               sta->ampdu_mlme.tid_state_tx[i] ?
+                               sta->ampdu_mlme.tid_tx[i]->dialog_token : 0);
+               p += scnprintf(p, sizeof(buf)+buf-p, "/SSN=%#.3x",
+                               sta->ampdu_mlme.tid_state_tx[i] ?
+                               sta->ampdu_mlme.tid_tx[i]->ssn : 0);
+               p += scnprintf(p, sizeof(buf)+buf-p, "/pending=%03d",
+                               sta->ampdu_mlme.tid_state_tx[i] ?
+                               skb_queue_len(&sta->ampdu_mlme.tid_tx[i]->pending) : 0);
+               p += scnprintf(p, sizeof(buf)+buf-p, "\n");
+       }
+       spin_unlock_bh(&sta->lock);
 
        return simple_read_from_buffer(userbuf, count, ppos, buf, p - buf);
 }
@@ -203,6 +196,22 @@ void ieee80211_sta_debugfs_add(struct sta_info *sta)
        DEBUGFS_ADD(inactive_ms);
        DEBUGFS_ADD(last_seq_ctrl);
        DEBUGFS_ADD(agg_status);
+       DEBUGFS_ADD(dev);
+       DEBUGFS_ADD(rx_packets);
+       DEBUGFS_ADD(tx_packets);
+       DEBUGFS_ADD(rx_bytes);
+       DEBUGFS_ADD(tx_bytes);
+       DEBUGFS_ADD(rx_duplicates);
+       DEBUGFS_ADD(rx_fragments);
+       DEBUGFS_ADD(rx_dropped);
+       DEBUGFS_ADD(tx_fragments);
+       DEBUGFS_ADD(tx_filtered);
+       DEBUGFS_ADD(tx_retry_failed);
+       DEBUGFS_ADD(tx_retry_count);
+       DEBUGFS_ADD(last_signal);
+       DEBUGFS_ADD(last_qual);
+       DEBUGFS_ADD(last_noise);
+       DEBUGFS_ADD(wep_weak_iv_count);
 }
 
 void ieee80211_sta_debugfs_remove(struct sta_info *sta)
@@ -212,6 +221,23 @@ void ieee80211_sta_debugfs_remove(struct sta_info *sta)
        DEBUGFS_DEL(inactive_ms);
        DEBUGFS_DEL(last_seq_ctrl);
        DEBUGFS_DEL(agg_status);
+       DEBUGFS_DEL(aid);
+       DEBUGFS_DEL(dev);
+       DEBUGFS_DEL(rx_packets);
+       DEBUGFS_DEL(tx_packets);
+       DEBUGFS_DEL(rx_bytes);
+       DEBUGFS_DEL(tx_bytes);
+       DEBUGFS_DEL(rx_duplicates);
+       DEBUGFS_DEL(rx_fragments);
+       DEBUGFS_DEL(rx_dropped);
+       DEBUGFS_DEL(tx_fragments);
+       DEBUGFS_DEL(tx_filtered);
+       DEBUGFS_DEL(tx_retry_failed);
+       DEBUGFS_DEL(tx_retry_count);
+       DEBUGFS_DEL(last_signal);
+       DEBUGFS_DEL(last_qual);
+       DEBUGFS_DEL(last_noise);
+       DEBUGFS_DEL(wep_weak_iv_count);
 
        debugfs_remove(sta->debugfs.dir);
        sta->debugfs.dir = NULL;
index f288d01..01ae759 100644 (file)
@@ -7,8 +7,7 @@
  *
  * mac80211 - events
  */
-
-#include <net/iw_handler.h>
+#include <net/cfg80211.h>
 #include "ieee80211_i.h"
 
 /*
  * driver or is still in the frame), it should provide that information.
  */
 void mac80211_ev_michael_mic_failure(struct ieee80211_sub_if_data *sdata, int keyidx,
-                                    struct ieee80211_hdr *hdr, const u8 *tsc)
+                                    struct ieee80211_hdr *hdr, const u8 *tsc,
+                                    gfp_t gfp)
 {
-       union iwreq_data wrqu;
-       char *buf = kmalloc(128, GFP_ATOMIC);
-
-       if (buf) {
-               /* TODO: needed parameters: count, key type, TSC */
-               sprintf(buf, "MLME-MICHAELMICFAILURE.indication("
-                       "keyid=%d %scast addr=%pM)",
-                       keyidx, hdr->addr1[0] & 0x01 ? "broad" : "uni",
-                       hdr->addr2);
-               memset(&wrqu, 0, sizeof(wrqu));
-               wrqu.data.length = strlen(buf);
-               wireless_send_event(sdata->dev, IWEVCUSTOM, &wrqu, buf);
-               kfree(buf);
-       }
-
        cfg80211_michael_mic_failure(sdata->dev, hdr->addr2,
                                     (hdr->addr1[0] & 0x01) ?
                                     NL80211_KEYTYPE_GROUP :
                                     NL80211_KEYTYPE_PAIRWISE,
-                                    keyidx, tsc);
+                                    keyidx, tsc, gfp);
 }
index 0b30277..15d5a53 100644 (file)
@@ -705,7 +705,7 @@ static void ieee80211_ibss_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
        struct ieee80211_mgmt *mgmt;
        u16 fc;
 
-       rx_status = (struct ieee80211_rx_status *) skb->cb;
+       rx_status = IEEE80211_SKB_RXCB(skb);
        mgmt = (struct ieee80211_mgmt *) skb->data;
        fc = le16_to_cpu(mgmt->frame_control);
 
@@ -836,8 +836,7 @@ void ieee80211_ibss_notify_scan_completed(struct ieee80211_local *local)
 }
 
 ieee80211_rx_result
-ieee80211_ibss_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb,
-                      struct ieee80211_rx_status *rx_status)
+ieee80211_ibss_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
 {
        struct ieee80211_local *local = sdata->local;
        struct ieee80211_mgmt *mgmt;
@@ -852,7 +851,6 @@ ieee80211_ibss_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb,
        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);
index 68eb505..327aabc 100644 (file)
@@ -227,35 +227,44 @@ struct mesh_preq_queue {
        u8 flags;
 };
 
+enum ieee80211_mgd_state {
+       IEEE80211_MGD_STATE_IDLE,
+       IEEE80211_MGD_STATE_PROBE,
+       IEEE80211_MGD_STATE_AUTH,
+       IEEE80211_MGD_STATE_ASSOC,
+};
+
+struct ieee80211_mgd_work {
+       struct list_head list;
+       struct ieee80211_bss *bss;
+       int ie_len;
+       u8 prev_bssid[ETH_ALEN];
+       u8 ssid[IEEE80211_MAX_SSID_LEN];
+       u8 ssid_len;
+       unsigned long timeout;
+       enum ieee80211_mgd_state state;
+       u16 auth_alg, auth_transaction;
+
+       int tries;
+
+       /* must be last */
+       u8 ie[0]; /* for auth or assoc frame, not probe */
+};
+
 /* 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)
-#define IEEE80211_STA_AUTHENTICATED    BIT(3)
-#define IEEE80211_STA_ASSOCIATED       BIT(4)
-#define IEEE80211_STA_PROBEREQ_POLL    BIT(5)
-#define IEEE80211_STA_CREATE_IBSS      BIT(6)
-#define IEEE80211_STA_CONTROL_PORT     BIT(7)
-#define IEEE80211_STA_WMM_ENABLED      BIT(8)
-/* hole at 9, please re-use */
-#define IEEE80211_STA_AUTO_SSID_SEL    BIT(10)
-#define IEEE80211_STA_AUTO_BSSID_SEL   BIT(11)
-#define IEEE80211_STA_AUTO_CHANNEL_SEL BIT(12)
-#define IEEE80211_STA_PRIVACY_INVOKED  BIT(13)
-#define IEEE80211_STA_TKIP_WEP_USED    BIT(14)
-#define IEEE80211_STA_CSA_RECEIVED     BIT(15)
-#define IEEE80211_STA_MFP_ENABLED      BIT(16)
-#define IEEE80211_STA_EXT_SME          BIT(17)
-/* flags for MLME request */
-#define IEEE80211_STA_REQ_SCAN 0
-#define IEEE80211_STA_REQ_AUTH 1
-#define IEEE80211_STA_REQ_RUN  2
+enum ieee80211_sta_flags {
+       IEEE80211_STA_PROBEREQ_POLL     = BIT(3),
+       IEEE80211_STA_CONTROL_PORT      = BIT(4),
+       IEEE80211_STA_WMM_ENABLED       = BIT(5),
+       IEEE80211_STA_DISABLE_11N       = BIT(6),
+       IEEE80211_STA_CSA_RECEIVED      = BIT(7),
+       IEEE80211_STA_MFP_ENABLED       = BIT(8),
+};
 
-/* 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)
-#define IEEE80211_AUTH_ALG_FT BIT(3)
+/* flags for MLME request */
+enum ieee80211_sta_request {
+       IEEE80211_STA_REQ_SCAN,
+};
 
 struct ieee80211_if_managed {
        struct timer_list timer;
@@ -264,49 +273,26 @@ struct ieee80211_if_managed {
        struct work_struct chswitch_work;
        struct work_struct beacon_loss_work;
 
-       u8 bssid[ETH_ALEN], prev_bssid[ETH_ALEN];
-
-       u8 ssid[IEEE80211_MAX_SSID_LEN];
-       size_t ssid_len;
+       struct mutex mtx;
+       struct ieee80211_bss *associated;
+       struct list_head work_list;
 
-       enum {
-               IEEE80211_STA_MLME_DISABLED,
-               IEEE80211_STA_MLME_DIRECT_PROBE,
-               IEEE80211_STA_MLME_AUTHENTICATE,
-               IEEE80211_STA_MLME_ASSOCIATE,
-               IEEE80211_STA_MLME_ASSOCIATED,
-       } state;
+       u8 bssid[ETH_ALEN];
 
        u16 aid;
-       u16 ap_capab, capab;
-       u8 *extra_ie; /* to be added to the end of AssocReq */
-       size_t extra_ie_len;
-
-       /* The last AssocReq/Resp IEs */
-       u8 *assocreq_ies, *assocresp_ies;
-       size_t assocreq_ies_len, assocresp_ies_len;
+       u16 capab;
 
        struct sk_buff_head skb_queue;
 
-       int assoc_scan_tries; /* number of scans done pre-association */
-       int direct_probe_tries; /* retries for direct probes */
-       int auth_tries; /* retries for auth req */
-       int assoc_tries; /* retries for assoc req */
-
        unsigned long timers_running; /* used for quiesce/restart */
        bool powersave; /* powersave requested for this iface */
 
        unsigned long request;
 
-       unsigned long last_probe;
        unsigned long last_beacon;
 
        unsigned int flags;
 
-       unsigned int auth_algs; /* bitfield of allowed auth algs */
-       int auth_alg; /* currently used IEEE 802.11 authentication algorithm */
-       int auth_transaction;
-
        u32 beacon_crc;
 
        enum {
@@ -316,10 +302,6 @@ struct ieee80211_if_managed {
        } mfp; /* management frame protection */
 
        int wmm_last_param_set;
-
-       /* Extra IE data for management frames */
-       u8 *sme_auth_ie;
-       size_t sme_auth_ie_len;
 };
 
 enum ieee80211_ibss_request {
@@ -478,20 +460,9 @@ struct ieee80211_sub_if_data {
        union {
                struct {
                        struct dentry *drop_unencrypted;
-                       struct dentry *state;
                        struct dentry *bssid;
-                       struct dentry *prev_bssid;
-                       struct dentry *ssid_len;
                        struct dentry *aid;
-                       struct dentry *ap_capab;
                        struct dentry *capab;
-                       struct dentry *extra_ie_len;
-                       struct dentry *auth_tries;
-                       struct dentry *assoc_tries;
-                       struct dentry *auth_algs;
-                       struct dentry *auth_alg;
-                       struct dentry *auth_transaction;
-                       struct dentry *flags;
                        struct dentry *force_unicast_rateidx;
                        struct dentry *max_ratectrl_rateidx;
                } sta;
@@ -942,16 +913,18 @@ extern const struct iw_handler_def ieee80211_iw_handler_def;
 
 /* STA code */
 void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata);
+int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
+                      struct cfg80211_auth_request *req);
+int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
+                       struct cfg80211_assoc_request *req);
+int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
+                        struct cfg80211_deauth_request *req,
+                        void *cookie);
+int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata,
+                          struct cfg80211_disassoc_request *req,
+                          void *cookie);
 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);
-int ieee80211_sta_deauthenticate(struct ieee80211_sub_if_data *sdata, u16 reason);
-int ieee80211_sta_disassociate(struct ieee80211_sub_if_data *sdata, u16 reason);
+                                         struct sk_buff *skb);
 void ieee80211_send_pspoll(struct ieee80211_local *local,
                           struct ieee80211_sub_if_data *sdata);
 void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency);
@@ -967,8 +940,7 @@ void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata);
 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);
+ieee80211_ibss_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb);
 struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata,
                                        u8 *bssid, u8 *addr, u32 supp_rates);
 int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,
@@ -983,16 +955,9 @@ int ieee80211_request_internal_scan(struct ieee80211_sub_if_data *sdata,
                                    const u8 *ssid, u8 ssid_len);
 int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata,
                           struct cfg80211_scan_request *req);
-int ieee80211_scan_results(struct ieee80211_local *local,
-                          struct iw_request_info *info,
-                          char *buf, size_t len);
 void ieee80211_scan_cancel(struct ieee80211_local *local);
 ieee80211_rx_result
-ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata,
-                 struct sk_buff *skb,
-                 struct ieee80211_rx_status *rx_status);
-int ieee80211_sta_set_extra_ie(struct ieee80211_sub_if_data *sdata,
-                              const char *ie, size_t len);
+ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb);
 
 void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local);
 struct ieee80211_bss *
@@ -1008,8 +973,6 @@ ieee80211_rx_bss_get(struct ieee80211_local *local, u8 *bssid, int freq,
                     u8 *ssid, u8 ssid_len);
 void ieee80211_rx_bss_put(struct ieee80211_local *local,
                          struct ieee80211_bss *bss);
-void ieee80211_rx_bss_remove(struct ieee80211_sub_if_data *sdata, u8 *bssid,
-                            int freq, u8 *ssid, u8 ssid_len);
 
 /* interface handling */
 int ieee80211_if_add(struct ieee80211_local *local, const char *name,
@@ -1092,7 +1055,8 @@ u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len,
 int ieee80211_frame_duration(struct ieee80211_local *local, size_t len,
                             int rate, int erp, int short_preamble);
 void mac80211_ev_michael_mic_failure(struct ieee80211_sub_if_data *sdata, int keyidx,
-                                    struct ieee80211_hdr *hdr, const u8 *tsc);
+                                    struct ieee80211_hdr *hdr, const u8 *tsc,
+                                    gfp_t gfp);
 void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata);
 void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb,
                      int encrypt);
index b7c8a44..4839a2d 100644 (file)
@@ -233,9 +233,6 @@ static int ieee80211_open(struct net_device *dev)
                ieee80211_configure_filter(local);
                netif_addr_unlock_bh(local->mdev);
                break;
-       case NL80211_IFTYPE_STATION:
-               sdata->u.mgd.flags &= ~IEEE80211_STA_PREV_BSSID_SET;
-               /* fall through */
        default:
                conf.vif = &sdata->vif;
                conf.type = sdata->vif.type;
@@ -366,18 +363,6 @@ 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.
         *
         * This must be done before calling ops->remove_interface()
@@ -462,7 +447,6 @@ static int ieee80211_stop(struct net_device *dev)
                netif_addr_unlock_bh(local->mdev);
                break;
        case NL80211_IFTYPE_STATION:
-               memset(sdata->u.mgd.bssid, 0, ETH_ALEN);
                del_timer_sync(&sdata->u.mgd.chswitch_timer);
                del_timer_sync(&sdata->u.mgd.timer);
                /*
@@ -485,12 +469,6 @@ static int ieee80211_stop(struct net_device *dev)
                 */
                synchronize_rcu();
                skb_queue_purge(&sdata->u.mgd.skb_queue);
-
-               sdata->u.mgd.flags &= ~(IEEE80211_STA_PRIVACY_INVOKED |
-                                       IEEE80211_STA_TKIP_WEP_USED);
-               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) {
@@ -652,11 +630,6 @@ static void ieee80211_teardown_sdata(struct net_device *dev)
                        kfree_skb(sdata->u.ibss.presp);
                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.sme_auth_ie);
-               break;
        case NL80211_IFTYPE_WDS:
        case NL80211_IFTYPE_AP_VLAN:
        case NL80211_IFTYPE_MONITOR:
@@ -939,7 +912,8 @@ u32 __ieee80211_recalc_idle(struct ieee80211_local *local)
                        continue;
                /* do not count disabled managed interfaces */
                if (sdata->vif.type == NL80211_IFTYPE_STATION &&
-                   sdata->u.mgd.state == IEEE80211_STA_MLME_DISABLED)
+                   !sdata->u.mgd.associated &&
+                   list_empty(&sdata->u.mgd.work_list))
                        continue;
                /* do not count unused IBSS interfaces */
                if (sdata->vif.type == NL80211_IFTYPE_ADHOC &&
index ce26756..659a42d 100644 (file)
@@ -67,6 +67,8 @@ static DECLARE_WORK(todo_work, key_todo);
  *
  * @key: key to add to do item for
  * @flag: todo flag(s)
+ *
+ * Must be called with IRQs or softirqs disabled.
  */
 static void add_todo(struct ieee80211_key *key, u32 flag)
 {
@@ -140,9 +142,9 @@ static void ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
        ret = drv_set_key(key->local, SET_KEY, &sdata->vif, sta, &key->conf);
 
        if (!ret) {
-               spin_lock(&todo_lock);
+               spin_lock_bh(&todo_lock);
                key->flags |= KEY_FLAG_UPLOADED_TO_HARDWARE;
-               spin_unlock(&todo_lock);
+               spin_unlock_bh(&todo_lock);
        }
 
        if (ret && ret != -ENOSPC && ret != -EOPNOTSUPP)
@@ -164,12 +166,12 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key)
        if (!key || !key->local->ops->set_key)
                return;
 
-       spin_lock(&todo_lock);
+       spin_lock_bh(&todo_lock);
        if (!(key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) {
-               spin_unlock(&todo_lock);
+               spin_unlock_bh(&todo_lock);
                return;
        }
-       spin_unlock(&todo_lock);
+       spin_unlock_bh(&todo_lock);
 
        sta = get_sta_for_key(key);
        sdata = key->sdata;
@@ -188,9 +190,9 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key)
                       wiphy_name(key->local->hw.wiphy),
                       key->conf.keyidx, sta ? sta->addr : bcast_addr, ret);
 
-       spin_lock(&todo_lock);
+       spin_lock_bh(&todo_lock);
        key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE;
-       spin_unlock(&todo_lock);
+       spin_unlock_bh(&todo_lock);
 }
 
 static void __ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata,
@@ -437,14 +439,14 @@ void ieee80211_key_link(struct ieee80211_key *key,
 
        __ieee80211_key_replace(sdata, sta, old_key, key);
 
-       spin_unlock_irqrestore(&sdata->local->key_lock, flags);
-
        /* free old key later */
        add_todo(old_key, KEY_FLAG_TODO_DELETE);
 
        add_todo(key, KEY_FLAG_TODO_ADD_DEBUGFS);
        if (netif_running(sdata->dev))
                add_todo(key, KEY_FLAG_TODO_HWACCEL_ADD);
+
+       spin_unlock_irqrestore(&sdata->local->key_lock, flags);
 }
 
 static void __ieee80211_key_free(struct ieee80211_key *key)
@@ -547,7 +549,7 @@ static void __ieee80211_key_todo(void)
         */
        synchronize_rcu();
 
-       spin_lock(&todo_lock);
+       spin_lock_bh(&todo_lock);
        while (!list_empty(&todo_list)) {
                key = list_first_entry(&todo_list, struct ieee80211_key, todo);
                list_del_init(&key->todo);
@@ -558,7 +560,7 @@ static void __ieee80211_key_todo(void)
                                          KEY_FLAG_TODO_HWACCEL_REMOVE |
                                          KEY_FLAG_TODO_DELETE);
                key->flags &= ~todoflags;
-               spin_unlock(&todo_lock);
+               spin_unlock_bh(&todo_lock);
 
                work_done = false;
 
@@ -591,9 +593,9 @@ static void __ieee80211_key_todo(void)
 
                WARN_ON(!work_done);
 
-               spin_lock(&todo_lock);
+               spin_lock_bh(&todo_lock);
        }
-       spin_unlock(&todo_lock);
+       spin_unlock_bh(&todo_lock);
 }
 
 void ieee80211_key_todo(void)
index 092a017..5b69f5f 100644 (file)
@@ -330,19 +330,16 @@ static void ieee80211_tasklet_handler(unsigned long data)
 {
        struct ieee80211_local *local = (struct ieee80211_local *) data;
        struct sk_buff *skb;
-       struct ieee80211_rx_status rx_status;
        struct ieee80211_ra_tid *ra_tid;
 
        while ((skb = skb_dequeue(&local->skb_queue)) ||
               (skb = skb_dequeue(&local->skb_queue_unreliable))) {
                switch (skb->pkt_type) {
                case IEEE80211_RX_MSG:
-                       /* status is in skb->cb */
-                       memcpy(&rx_status, skb->cb, sizeof(rx_status));
                        /* Clear skb->pkt_type in order to not confuse kernel
                         * netstack. */
                        skb->pkt_type = 0;
-                       __ieee80211_rx(local_to_hw(local), skb, &rx_status);
+                       ieee80211_rx(local_to_hw(local), skb);
                        break;
                case IEEE80211_TX_STATUS_MSG:
                        skb->pkt_type = 0;
index 11cf45b..542ea02 100644 (file)
@@ -568,7 +568,7 @@ static void ieee80211_mesh_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
 
        ifmsh = &sdata->u.mesh;
 
-       rx_status = (struct ieee80211_rx_status *) skb->cb;
+       rx_status = IEEE80211_SKB_RXCB(skb);
        mgmt = (struct ieee80211_mgmt *) skb->data;
        stype = le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_STYPE;
 
@@ -671,8 +671,7 @@ void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata)
 }
 
 ieee80211_rx_result
-ieee80211_mesh_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb,
-                      struct ieee80211_rx_status *rx_status)
+ieee80211_mesh_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
 {
        struct ieee80211_local *local = sdata->local;
        struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
@@ -689,7 +688,6 @@ ieee80211_mesh_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb,
        case IEEE80211_STYPE_PROBE_RESP:
        case IEEE80211_STYPE_BEACON:
        case IEEE80211_STYPE_ACTION:
-               memcpy(skb->cb, rx_status, sizeof(*rx_status));
                skb_queue_tail(&ifmsh->skb_queue, skb);
                queue_work(local->hw.workqueue, &ifmsh->work);
                return RX_QUEUED;
index c7d7281..2a2ed18 100644 (file)
@@ -208,8 +208,7 @@ void ieee80211s_init(void);
 void ieee80211s_stop(void);
 void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata);
 ieee80211_rx_result
-ieee80211_mesh_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb,
-                      struct ieee80211_rx_status *rx_status);
+ieee80211_mesh_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb);
 void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata);
 void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata);
 
index aca22b0..c9db964 100644 (file)
 #include "rate.h"
 #include "led.h"
 
-#define IEEE80211_ASSOC_SCANS_MAX_TRIES 2
 #define IEEE80211_AUTH_TIMEOUT (HZ / 5)
 #define IEEE80211_AUTH_MAX_TRIES 3
 #define IEEE80211_ASSOC_TIMEOUT (HZ / 5)
 #define IEEE80211_ASSOC_MAX_TRIES 3
 #define IEEE80211_MONITORING_INTERVAL (2 * HZ)
 #define IEEE80211_PROBE_WAIT (HZ / 5)
-#define IEEE80211_PROBE_IDLE_TIME (60 * HZ)
-#define IEEE80211_RETRY_AUTH_INTERVAL (1 * HZ)
 
 #define TMR_RUNNING_TIMER      0
 #define TMR_RUNNING_CHANSW     1
 
+/*
+ * All cfg80211 functions have to be called outside a locked
+ * section so that they can acquire a lock themselves... This
+ * is much simpler than queuing up things in cfg80211, but we
+ * do need some indirection for that here.
+ */
+enum rx_mgmt_action {
+       /* no action required */
+       RX_MGMT_NONE,
+
+       /* caller must call cfg80211_send_rx_auth() */
+       RX_MGMT_CFG80211_AUTH,
+
+       /* caller must call cfg80211_send_rx_assoc() */
+       RX_MGMT_CFG80211_ASSOC,
+
+       /* caller must call cfg80211_send_deauth() */
+       RX_MGMT_CFG80211_DEAUTH,
+
+       /* caller must call cfg80211_send_disassoc() */
+       RX_MGMT_CFG80211_DISASSOC,
+
+       /* caller must call cfg80211_auth_timeout() & free work */
+       RX_MGMT_CFG80211_AUTH_TO,
+
+       /* caller must call cfg80211_assoc_timeout() & free work */
+       RX_MGMT_CFG80211_ASSOC_TO,
+};
+
 /* utils */
-static int ecw2cw(int ecw)
+static inline void ASSERT_MGD_MTX(struct ieee80211_if_managed *ifmgd)
 {
-       return (1 << ecw) - 1;
+       WARN_ON(!mutex_is_locked(&ifmgd->mtx));
 }
 
-static u8 *ieee80211_bss_get_ie(struct ieee80211_bss *bss, u8 ie)
+static int ecw2cw(int ecw)
 {
-       u8 *end, *pos;
-
-       pos = bss->cbss.information_elements;
-       if (pos == NULL)
-               return NULL;
-       end = pos + bss->cbss.len_information_elements;
-
-       while (pos + 1 < end) {
-               if (pos + 2 + pos[1] > end)
-                       break;
-               if (pos[0] == ie)
-                       return pos;
-               pos += 2 + pos[1];
-       }
-
-       return NULL;
+       return (1 << ecw) - 1;
 }
 
 static int ieee80211_compatible_rates(struct ieee80211_bss *bss,
@@ -94,11 +105,10 @@ static int ieee80211_compatible_rates(struct ieee80211_bss *bss,
  */
 static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata,
                               struct ieee80211_ht_info *hti,
-                              u16 ap_ht_cap_flags)
+                              const u8 *bssid, u16 ap_ht_cap_flags)
 {
        struct ieee80211_local *local = sdata->local;
        struct ieee80211_supported_band *sband;
-       struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
        struct sta_info *sta;
        u32 changed = 0;
        u16 ht_opmode;
@@ -147,12 +157,10 @@ static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata,
                ieee80211_hw_config(local, 0);
 
                rcu_read_lock();
-
-               sta = sta_info_get(local, ifmgd->bssid);
+               sta = sta_info_get(local, bssid);
                if (sta)
                        rate_control_rate_update(local, sband, sta,
                                                 IEEE80211_RC_HT_CHANGED);
-
                rcu_read_unlock();
         }
 
@@ -175,23 +183,24 @@ static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata,
 
 /* frame sending functions */
 
-static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
+static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata,
+                                struct ieee80211_mgd_work *wk)
 {
        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
        struct ieee80211_local *local = sdata->local;
        struct sk_buff *skb;
        struct ieee80211_mgmt *mgmt;
-       u8 *pos, *ies, *ht_ie;
+       u8 *pos;
+       const u8 *ies, *ht_ie;
        int i, len, count, rates_len, supp_rates_len;
        u16 capab;
-       struct ieee80211_bss *bss;
        int wmm = 0;
        struct ieee80211_supported_band *sband;
        u32 rates = 0;
 
        skb = dev_alloc_skb(local->hw.extra_tx_headroom +
-                           sizeof(*mgmt) + 200 + ifmgd->extra_ie_len +
-                           ifmgd->ssid_len);
+                           sizeof(*mgmt) + 200 + wk->ie_len +
+                           wk->ssid_len);
        if (!skb) {
                printk(KERN_DEBUG "%s: failed to allocate buffer for assoc "
                       "frame\n", sdata->dev->name);
@@ -210,45 +219,35 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
                        capab |= WLAN_CAPABILITY_SHORT_PREAMBLE;
        }
 
-       bss = ieee80211_rx_bss_get(local, ifmgd->bssid,
-                                  local->hw.conf.channel->center_freq,
-                                  ifmgd->ssid, ifmgd->ssid_len);
-       if (bss) {
-               if (bss->cbss.capability & WLAN_CAPABILITY_PRIVACY)
-                       capab |= WLAN_CAPABILITY_PRIVACY;
-               if (bss->wmm_used)
-                       wmm = 1;
+       if (wk->bss->cbss.capability & WLAN_CAPABILITY_PRIVACY)
+               capab |= WLAN_CAPABILITY_PRIVACY;
+       if (wk->bss->wmm_used)
+               wmm = 1;
 
-               /* get all rates supported by the device and the AP as
-                * some APs don't like getting a superset of their rates
-                * in the association request (e.g. D-Link DAP 1353 in
-                * b-only mode) */
-               rates_len = ieee80211_compatible_rates(bss, sband, &rates);
+       /* get all rates supported by the device and the AP as
+        * some APs don't like getting a superset of their rates
+        * in the association request (e.g. D-Link DAP 1353 in
+        * b-only mode) */
+       rates_len = ieee80211_compatible_rates(wk->bss, sband, &rates);
 
-               if ((bss->cbss.capability & WLAN_CAPABILITY_SPECTRUM_MGMT) &&
-                   (local->hw.flags & IEEE80211_HW_SPECTRUM_MGMT))
-                       capab |= WLAN_CAPABILITY_SPECTRUM_MGMT;
-
-               ieee80211_rx_bss_put(local, bss);
-       } else {
-               rates = ~0;
-               rates_len = sband->n_bitrates;
-       }
+       if ((wk->bss->cbss.capability & WLAN_CAPABILITY_SPECTRUM_MGMT) &&
+           (local->hw.flags & IEEE80211_HW_SPECTRUM_MGMT))
+               capab |= WLAN_CAPABILITY_SPECTRUM_MGMT;
 
        mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
        memset(mgmt, 0, 24);
-       memcpy(mgmt->da, ifmgd->bssid, ETH_ALEN);
+       memcpy(mgmt->da, wk->bss->cbss.bssid, ETH_ALEN);
        memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
-       memcpy(mgmt->bssid, ifmgd->bssid, ETH_ALEN);
+       memcpy(mgmt->bssid, wk->bss->cbss.bssid, ETH_ALEN);
 
-       if (ifmgd->flags & IEEE80211_STA_PREV_BSSID_SET) {
+       if (!is_zero_ether_addr(wk->prev_bssid)) {
                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, ifmgd->prev_bssid,
+               memcpy(mgmt->u.reassoc_req.current_ap, wk->prev_bssid,
                       ETH_ALEN);
        } else {
                skb_put(skb, 4);
@@ -260,10 +259,10 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
        }
 
        /* SSID */
-       ies = pos = skb_put(skb, 2 + ifmgd->ssid_len);
+       ies = pos = skb_put(skb, 2 + wk->ssid_len);
        *pos++ = WLAN_EID_SSID;
-       *pos++ = ifmgd->ssid_len;
-       memcpy(pos, ifmgd->ssid, ifmgd->ssid_len);
+       *pos++ = wk->ssid_len;
+       memcpy(pos, wk->ssid, wk->ssid_len);
 
        /* add all rates which were marked to be used above */
        supp_rates_len = rates_len;
@@ -318,9 +317,9 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
                }
        }
 
-       if (ifmgd->extra_ie) {
-               pos = skb_put(skb, ifmgd->extra_ie_len);
-               memcpy(pos, ifmgd->extra_ie, ifmgd->extra_ie_len);
+       if (wk->ie_len && wk->ie) {
+               pos = skb_put(skb, wk->ie_len);
+               memcpy(pos, wk->ie, wk->ie_len);
        }
 
        if (wmm && (ifmgd->flags & IEEE80211_STA_WMM_ENABLED)) {
@@ -345,9 +344,9 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
         */
        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 = ieee80211_bss_get_ie(&wk->bss->cbss, WLAN_EID_HT_INFORMATION)) &&
            ht_ie[1] >= sizeof(struct ieee80211_ht_info) &&
-           (!(ifmgd->flags & IEEE80211_STA_TKIP_WEP_USED))) {
+           (!(ifmgd->flags & IEEE80211_STA_DISABLE_11N))) {
                struct ieee80211_ht_info *ht_info =
                        (struct ieee80211_ht_info *)(ht_ie + 2);
                u16 cap = sband->ht_cap.cap;
@@ -382,18 +381,13 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
                memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs));
        }
 
-       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);
 }
 
 
 static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata,
-                                          u16 stype, u16 reason)
+                                          const u8 *bssid, u16 stype, u16 reason,
+                                          void *cookie)
 {
        struct ieee80211_local *local = sdata->local;
        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
@@ -410,18 +404,18 @@ 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, ifmgd->bssid, ETH_ALEN);
+       memcpy(mgmt->da, bssid, ETH_ALEN);
        memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
-       memcpy(mgmt->bssid, ifmgd->bssid, ETH_ALEN);
+       memcpy(mgmt->bssid, 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 */
        mgmt->u.deauth.reason_code = cpu_to_le16(reason);
 
        if (stype == IEEE80211_STYPE_DEAUTH)
-               cfg80211_send_deauth(sdata->dev, (u8 *) mgmt, skb->len);
+               cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, skb->len, cookie);
        else
-               cfg80211_send_disassoc(sdata->dev, (u8 *) mgmt, skb->len);
+               cfg80211_send_disassoc(sdata->dev, (u8 *)mgmt, skb->len, cookie);
        ieee80211_tx_skb(sdata, skb, ifmgd->flags & IEEE80211_STA_MFP_ENABLED);
 }
 
@@ -494,28 +488,26 @@ static void ieee80211_chswitch_work(struct work_struct *work)
 {
        struct ieee80211_sub_if_data *sdata =
                container_of(work, struct ieee80211_sub_if_data, u.mgd.chswitch_work);
-       struct ieee80211_bss *bss;
        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
 
        if (!netif_running(sdata->dev))
                return;
 
-       bss = ieee80211_rx_bss_get(sdata->local, ifmgd->bssid,
-                                  sdata->local->hw.conf.channel->center_freq,
-                                  ifmgd->ssid, ifmgd->ssid_len);
-       if (!bss)
-               goto exit;
+       mutex_lock(&ifmgd->mtx);
+       if (!ifmgd->associated)
+               goto out;
 
        sdata->local->oper_channel = sdata->local->csa_channel;
+       ieee80211_hw_config(sdata->local, IEEE80211_CONF_CHANGE_CHANNEL);
+
        /* XXX: shouldn't really modify cfg80211-owned data! */
-       if (!ieee80211_hw_config(sdata->local, IEEE80211_CONF_CHANGE_CHANNEL))
-               bss->cbss.channel = sdata->local->oper_channel;
+       ifmgd->associated->cbss.channel = sdata->local->oper_channel;
 
-       ieee80211_rx_bss_put(sdata->local, bss);
-exit:
-       ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED;
        ieee80211_wake_queues_by_reason(&sdata->local->hw,
                                        IEEE80211_QUEUE_STOP_REASON_CSA);
+ out:
+       ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED;
+       mutex_unlock(&ifmgd->mtx);
 }
 
 static void ieee80211_chswitch_timer(unsigned long data)
@@ -540,7 +532,9 @@ void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
        int new_freq = ieee80211_channel_to_frequency(sw_elem->new_ch_num);
 
-       if (ifmgd->state != IEEE80211_STA_MLME_ASSOCIATED)
+       ASSERT_MGD_MTX(ifmgd);
+
+       if (!ifmgd->associated)
                return;
 
        if (sdata->local->sw_scanning || sdata->local->hw_scanning)
@@ -651,7 +645,7 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency)
        }
 
        if (count == 1 && found->u.mgd.powersave &&
-           (found->u.mgd.flags & IEEE80211_STA_ASSOCIATED) &&
+           found->u.mgd.associated && list_empty(&found->u.mgd.work_list) &&
            !(found->u.mgd.flags & IEEE80211_STA_PROBEREQ_POLL)) {
                s32 beaconint_us;
 
@@ -806,9 +800,6 @@ static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata,
                                           u16 capab, bool erp_valid, u8 erp)
 {
        struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf;
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-       struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
-#endif
        u32 changed = 0;
        bool use_protection;
        bool use_short_preamble;
@@ -825,42 +816,16 @@ static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata,
        use_short_slot = !!(capab & WLAN_CAPABILITY_SHORT_SLOT_TIME);
 
        if (use_protection != bss_conf->use_cts_prot) {
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-               if (net_ratelimit()) {
-                       printk(KERN_DEBUG "%s: CTS protection %s (BSSID=%pM)\n",
-                              sdata->dev->name,
-                              use_protection ? "enabled" : "disabled",
-                              ifmgd->bssid);
-               }
-#endif
                bss_conf->use_cts_prot = use_protection;
                changed |= BSS_CHANGED_ERP_CTS_PROT;
        }
 
        if (use_short_preamble != bss_conf->use_short_preamble) {
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-               if (net_ratelimit()) {
-                       printk(KERN_DEBUG "%s: switched to %s barker preamble"
-                              " (BSSID=%pM)\n",
-                              sdata->dev->name,
-                              use_short_preamble ? "short" : "long",
-                              ifmgd->bssid);
-               }
-#endif
                bss_conf->use_short_preamble = use_short_preamble;
                changed |= BSS_CHANGED_ERP_PREAMBLE;
        }
 
        if (use_short_slot != bss_conf->use_short_slot) {
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-               if (net_ratelimit()) {
-                       printk(KERN_DEBUG "%s: switched to %s slot time"
-                              " (BSSID=%pM)\n",
-                              sdata->dev->name,
-                              use_short_slot ? "short" : "long",
-                              ifmgd->bssid);
-               }
-#endif
                bss_conf->use_short_slot = use_short_slot;
                changed |= BSS_CHANGED_ERP_SLOT;
        }
@@ -868,105 +833,25 @@ 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)
-{
-       union iwreq_data wrqu;
-
-       memset(&wrqu, 0, sizeof(wrqu));
-       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_managed *ifmgd = &sdata->u.mgd;
-       char *buf;
-       size_t len;
-       int i;
-       union iwreq_data wrqu;
-
-       if (!ifmgd->assocreq_ies && !ifmgd->assocresp_ies)
-               return;
-
-       buf = kmalloc(50 + 2 * (ifmgd->assocreq_ies_len +
-                               ifmgd->assocresp_ies_len), GFP_KERNEL);
-       if (!buf)
-               return;
-
-       len = sprintf(buf, "ASSOCINFO(");
-       if (ifmgd->assocreq_ies) {
-               len += sprintf(buf + len, "ReqIEs=");
-               for (i = 0; i < ifmgd->assocreq_ies_len; i++) {
-                       len += sprintf(buf + len, "%02x",
-                                      ifmgd->assocreq_ies[i]);
-               }
-       }
-       if (ifmgd->assocresp_ies) {
-               if (ifmgd->assocreq_ies)
-                       len += sprintf(buf + len, " ");
-               len += sprintf(buf + len, "RespIEs=");
-               for (i = 0; i < ifmgd->assocresp_ies_len; i++) {
-                       len += sprintf(buf + len, "%02x",
-                                      ifmgd->assocresp_ies[i]);
-               }
-       }
-       len += sprintf(buf + len, ")");
-
-       if (len > IW_CUSTOM_MAX) {
-               len = sprintf(buf, "ASSOCRESPIE=");
-               for (i = 0; i < ifmgd->assocresp_ies_len; i++) {
-                       len += sprintf(buf + len, "%02x",
-                                      ifmgd->assocresp_ies[i]);
-               }
-       }
-
-       if (len <= IW_CUSTOM_MAX) {
-               memset(&wrqu, 0, sizeof(wrqu));
-               wrqu.data.length = len;
-               wireless_send_event(sdata->dev, IWEVCUSTOM, &wrqu, buf);
-       }
-
-       kfree(buf);
-}
-
-
 static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
+                                    struct ieee80211_bss *bss,
                                     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;
-       ifmgd->flags |= IEEE80211_STA_ASSOCIATED;
+       /* set timing information */
+       sdata->vif.bss_conf.beacon_int = bss->cbss.beacon_interval;
+       sdata->vif.bss_conf.timestamp = bss->cbss.tsf;
+       sdata->vif.bss_conf.dtim_period = bss->dtim_period;
 
-       bss = ieee80211_rx_bss_get(local, ifmgd->bssid,
-                                  conf->channel->center_freq,
-                                  ifmgd->ssid, ifmgd->ssid_len);
-       if (bss) {
-               /* set timing information */
-               sdata->vif.bss_conf.beacon_int = bss->cbss.beacon_interval;
-               sdata->vif.bss_conf.timestamp = bss->cbss.tsf;
-               sdata->vif.bss_conf.dtim_period = bss->dtim_period;
+       bss_info_changed |= BSS_CHANGED_BEACON_INT;
+       bss_info_changed |= ieee80211_handle_bss_capability(sdata,
+               bss->cbss.capability, bss->has_erp_value, bss->erp_value);
 
-               bss_info_changed |= BSS_CHANGED_BEACON_INT;
-               bss_info_changed |= ieee80211_handle_bss_capability(sdata,
-                       bss->cbss.capability, bss->has_erp_value, bss->erp_value);
+       sdata->u.mgd.associated = bss;
+       memcpy(sdata->u.mgd.bssid, bss->cbss.bssid, ETH_ALEN);
 
-               cfg80211_hold_bss(&bss->cbss);
-
-               ieee80211_rx_bss_put(local, bss);
-       }
-
-       ifmgd->flags |= IEEE80211_STA_PREV_BSSID_SET;
-       memcpy(ifmgd->prev_bssid, sdata->u.mgd.bssid, ETH_ALEN);
-       ieee80211_sta_send_associnfo(sdata);
-
-       ifmgd->last_probe = jiffies;
        ieee80211_led_assoc(local, 1);
 
        sdata->vif.bss_conf.assoc = 1;
@@ -991,167 +876,135 @@ 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);
 }
 
-static void ieee80211_direct_probe(struct ieee80211_sub_if_data *sdata)
+static enum rx_mgmt_action __must_check
+ieee80211_direct_probe(struct ieee80211_sub_if_data *sdata,
+                      struct ieee80211_mgd_work *wk)
 {
        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
        struct ieee80211_local *local = sdata->local;
 
-       ifmgd->direct_probe_tries++;
-       if (ifmgd->direct_probe_tries > IEEE80211_AUTH_MAX_TRIES) {
+       wk->tries++;
+       if (wk->tries > IEEE80211_AUTH_MAX_TRIES) {
                printk(KERN_DEBUG "%s: direct probe to AP %pM timed out\n",
-                      sdata->dev->name, ifmgd->bssid);
-               ifmgd->state = IEEE80211_STA_MLME_DISABLED;
-               ieee80211_recalc_idle(local);
-               cfg80211_send_auth_timeout(sdata->dev, ifmgd->bssid);
+                      sdata->dev->name, wk->bss->cbss.bssid);
 
                /*
                 * Most likely AP is not in the range so remove the
-                * bss information associated to the AP
+                * bss struct for that AP.
                 */
-               ieee80211_rx_bss_remove(sdata, ifmgd->bssid,
-                               sdata->local->hw.conf.channel->center_freq,
-                               ifmgd->ssid, ifmgd->ssid_len);
+               cfg80211_unlink_bss(local->hw.wiphy, &wk->bss->cbss);
 
                /*
                 * We might have a pending scan which had no chance to run yet
-                * due to state == IEEE80211_STA_MLME_DIRECT_PROBE.
-                * Hence, queue the STAs work again
+                * due to work needing to be done. Hence, queue the STAs work
+                * again for that.
                 */
                queue_work(local->hw.workqueue, &ifmgd->work);
-               return;
+               return RX_MGMT_CFG80211_AUTH_TO;
        }
 
-       printk(KERN_DEBUG "%s: direct probe to AP %pM try %d\n",
-                       sdata->dev->name, ifmgd->bssid,
-                       ifmgd->direct_probe_tries);
-
-       ifmgd->state = IEEE80211_STA_MLME_DIRECT_PROBE;
+       printk(KERN_DEBUG "%s: direct probe to AP %pM (try %d)\n",
+                       sdata->dev->name, wk->bss->cbss.bssid,
+                       wk->tries);
 
-       /* Direct probe is sent to broadcast address as some APs
+       /*
+        * 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,
-                                ifmgd->ssid, ifmgd->ssid_len, NULL, 0);
+       ieee80211_send_probe_req(sdata, NULL, wk->ssid, wk->ssid_len, NULL, 0);
+
+       wk->timeout = jiffies + IEEE80211_AUTH_TIMEOUT;
+       mod_timer(&ifmgd->timer, wk->timeout);
 
-       mod_timer(&ifmgd->timer, jiffies + IEEE80211_AUTH_TIMEOUT);
+       return RX_MGMT_NONE;
 }
 
 
-static void ieee80211_authenticate(struct ieee80211_sub_if_data *sdata)
+static enum rx_mgmt_action __must_check
+ieee80211_authenticate(struct ieee80211_sub_if_data *sdata,
+                      struct ieee80211_mgd_work *wk)
 {
        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
        struct ieee80211_local *local = sdata->local;
-       u8 *ies;
-       size_t ies_len;
 
-       ifmgd->auth_tries++;
-       if (ifmgd->auth_tries > IEEE80211_AUTH_MAX_TRIES) {
+       wk->tries++;
+       if (wk->tries > IEEE80211_AUTH_MAX_TRIES) {
                printk(KERN_DEBUG "%s: authentication with AP %pM"
                       " timed out\n",
-                      sdata->dev->name, ifmgd->bssid);
-               ifmgd->state = IEEE80211_STA_MLME_DISABLED;
-               ieee80211_recalc_idle(local);
-               cfg80211_send_auth_timeout(sdata->dev, ifmgd->bssid);
-               ieee80211_rx_bss_remove(sdata, ifmgd->bssid,
-                               sdata->local->hw.conf.channel->center_freq,
-                               ifmgd->ssid, ifmgd->ssid_len);
+                      sdata->dev->name, wk->bss->cbss.bssid);
+
+               /*
+                * Most likely AP is not in the range so remove the
+                * bss struct for that AP.
+                */
+               cfg80211_unlink_bss(local->hw.wiphy, &wk->bss->cbss);
 
                /*
                 * We might have a pending scan which had no chance to run yet
-                * due to state == IEEE80211_STA_MLME_AUTHENTICATE.
-                * Hence, queue the STAs work again
+                * due to work needing to be done. Hence, queue the STAs work
+                * again for that.
                 */
                queue_work(local->hw.workqueue, &ifmgd->work);
-               return;
+               return RX_MGMT_CFG80211_AUTH_TO;
        }
 
-       ifmgd->state = IEEE80211_STA_MLME_AUTHENTICATE;
-       printk(KERN_DEBUG "%s: authenticate with AP %pM\n",
-              sdata->dev->name, ifmgd->bssid);
+       printk(KERN_DEBUG "%s: authenticate with AP %pM (try %d)\n",
+              sdata->dev->name, wk->bss->cbss.bssid, wk->tries);
 
-       if (ifmgd->flags & IEEE80211_STA_EXT_SME) {
-               ies = ifmgd->sme_auth_ie;
-               ies_len = ifmgd->sme_auth_ie_len;
-       } else {
-               ies = NULL;
-               ies_len = 0;
-       }
-       ieee80211_send_auth(sdata, 1, ifmgd->auth_alg, ies, ies_len,
-                           ifmgd->bssid, 0);
-       ifmgd->auth_transaction = 2;
+       ieee80211_send_auth(sdata, 1, wk->auth_alg, wk->ie, wk->ie_len,
+                           wk->bss->cbss.bssid, 0);
+       wk->auth_transaction = 2;
 
-       mod_timer(&ifmgd->timer, jiffies + IEEE80211_AUTH_TIMEOUT);
+       wk->timeout = jiffies + IEEE80211_AUTH_TIMEOUT;
+       mod_timer(&ifmgd->timer, wk->timeout);
+
+       return RX_MGMT_NONE;
 }
 
-/*
- * The disassoc 'reason' argument can be either our own reason
- * if self disconnected or a reason code from the AP.
- */
 static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
-                                  bool deauth, bool self_disconnected,
-                                  u16 reason)
+                                  const u8 *bssid, bool deauth)
 {
        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;
        struct sta_info *sta;
        u32 changed = 0, config_changed = 0;
 
-       if (deauth) {
-               ifmgd->direct_probe_tries = 0;
-               ifmgd->auth_tries = 0;
-       }
-       ifmgd->assoc_scan_tries = 0;
-       ifmgd->assoc_tries = 0;
+       ASSERT_MGD_MTX(ifmgd);
+
+       ifmgd->associated = NULL;
+       memset(ifmgd->bssid, 0, ETH_ALEN);
+
+       /*
+        * we need to commit the associated = NULL change because the
+        * scan code uses that to determine whether this iface should
+        * go to/wake up from powersave or not -- and could otherwise
+        * wake the queues erroneously.
+        */
+       smp_mb();
+
+       /*
+        * Thus, we can only afterwards stop the queues -- to account
+        * for the case where another CPU is finishing a scan at this
+        * time -- we don't want the scan code to enable queues.
+        */
 
        netif_tx_stop_all_queues(sdata->dev);
        netif_carrier_off(sdata->dev);
 
        rcu_read_lock();
-       sta = sta_info_get(local, ifmgd->bssid);
+       sta = sta_info_get(local, bssid);
        if (sta)
                ieee80211_sta_tear_down_BA_sessions(sta);
        rcu_read_unlock();
 
-       bss = ieee80211_rx_bss_get(local, ifmgd->bssid,
-                                  conf->channel->center_freq,
-                                  ifmgd->ssid, ifmgd->ssid_len);
-
-       if (bss) {
-               cfg80211_unhold_bss(&bss->cbss);
-               ieee80211_rx_bss_put(local, bss);
-       }
-
-       if (self_disconnected) {
-               if (deauth)
-                       ieee80211_send_deauth_disassoc(sdata,
-                               IEEE80211_STYPE_DEAUTH, reason);
-               else
-                       ieee80211_send_deauth_disassoc(sdata,
-                               IEEE80211_STYPE_DISASSOC, reason);
-       }
-
-       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);
-
-       if (self_disconnected || reason == WLAN_REASON_DISASSOC_STA_HAS_LEFT) {
-               ifmgd->state = IEEE80211_STA_MLME_DISABLED;
-               ieee80211_rx_bss_remove(sdata, ifmgd->bssid,
-                               sdata->local->hw.conf.channel->center_freq,
-                               ifmgd->ssid, ifmgd->ssid_len);
-       }
-
        ieee80211_set_wmm_default(sdata);
 
        ieee80211_recalc_idle(local);
@@ -1180,7 +1033,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
 
        rcu_read_lock();
 
-       sta = sta_info_get(local, ifmgd->bssid);
+       sta = sta_info_get(local, bssid);
        if (!sta) {
                rcu_read_unlock();
                return;
@@ -1193,83 +1046,42 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
        sta_info_destroy(sta);
 }
 
-static int ieee80211_sta_wep_configured(struct ieee80211_sub_if_data *sdata)
-{
-       if (!sdata || !sdata->default_key ||
-           sdata->default_key->conf.alg != ALG_WEP)
-               return 0;
-       return 1;
-}
-
-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 (!ifmgd || (ifmgd->flags & IEEE80211_STA_EXT_SME))
-               return 0;
-
-       bss = ieee80211_rx_bss_get(local, ifmgd->bssid,
-                                  local->hw.conf.channel->center_freq,
-                                  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 = !!(ifmgd->flags & IEEE80211_STA_PRIVACY_INVOKED);
-
-       ieee80211_rx_bss_put(local, bss);
-
-       if ((bss_privacy == wep_privacy) || (bss_privacy == privacy_invoked))
-               return 0;
-
-       return 1;
-}
-
-static void ieee80211_associate(struct ieee80211_sub_if_data *sdata)
+static enum rx_mgmt_action __must_check
+ieee80211_associate(struct ieee80211_sub_if_data *sdata,
+                   struct ieee80211_mgd_work *wk)
 {
        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
        struct ieee80211_local *local = sdata->local;
 
-       ifmgd->assoc_tries++;
-       if (ifmgd->assoc_tries > IEEE80211_ASSOC_MAX_TRIES) {
+       wk->tries++;
+       if (wk->tries > IEEE80211_ASSOC_MAX_TRIES) {
                printk(KERN_DEBUG "%s: association with AP %pM"
                       " timed out\n",
-                      sdata->dev->name, ifmgd->bssid);
-               ifmgd->state = IEEE80211_STA_MLME_DISABLED;
-               ieee80211_recalc_idle(local);
-               cfg80211_send_assoc_timeout(sdata->dev, ifmgd->bssid);
-               ieee80211_rx_bss_remove(sdata, ifmgd->bssid,
-                               sdata->local->hw.conf.channel->center_freq,
-                               ifmgd->ssid, ifmgd->ssid_len);
+                      sdata->dev->name, wk->bss->cbss.bssid);
+
+               /*
+                * Most likely AP is not in the range so remove the
+                * bss struct for that AP.
+                */
+               cfg80211_unlink_bss(local->hw.wiphy, &wk->bss->cbss);
+
                /*
                 * We might have a pending scan which had no chance to run yet
-                * due to state == IEEE80211_STA_MLME_ASSOCIATE.
-                * Hence, queue the STAs work again
+                * due to work needing to be done. Hence, queue the STAs work
+                * again for that.
                 */
                queue_work(local->hw.workqueue, &ifmgd->work);
-               return;
+               return RX_MGMT_CFG80211_ASSOC_TO;
        }
 
-       ifmgd->state = IEEE80211_STA_MLME_ASSOCIATE;
-       printk(KERN_DEBUG "%s: associate with AP %pM\n",
-              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);
-               ifmgd->state = IEEE80211_STA_MLME_DISABLED;
-               ieee80211_recalc_idle(local);
-               return;
-       }
+       printk(KERN_DEBUG "%s: associate with AP %pM (try %d)\n",
+              sdata->dev->name, wk->bss->cbss.bssid, wk->tries);
+       ieee80211_send_assoc(sdata, wk);
 
-       ieee80211_send_assoc(sdata);
+       wk->timeout = jiffies + IEEE80211_ASSOC_TIMEOUT;
+       mod_timer(&ifmgd->timer, wk->timeout);
 
-       mod_timer(&ifmgd->timer, jiffies + IEEE80211_ASSOC_TIMEOUT);
+       return RX_MGMT_NONE;
 }
 
 void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata,
@@ -1294,6 +1106,7 @@ void ieee80211_beacon_loss_work(struct work_struct *work)
                container_of(work, struct ieee80211_sub_if_data,
                             u.mgd.beacon_loss_work);
        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+       const u8 *ssid;
 
        /*
         * The driver has already reported this event and we have
@@ -1306,12 +1119,15 @@ void ieee80211_beacon_loss_work(struct work_struct *work)
        if (ifmgd->flags & IEEE80211_STA_PROBEREQ_POLL)
                return;
 
+       mutex_lock(&ifmgd->mtx);
+
+       if (!ifmgd->associated)
+               goto out;
+
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-       if (net_ratelimit()) {
-               printk(KERN_DEBUG "%s: driver reports beacon loss from AP %pM "
-                      "- sending probe request\n", sdata->dev->name,
-                      sdata->u.mgd.bssid);
-       }
+       if (net_ratelimit())
+               printk(KERN_DEBUG "%s: driver reports beacon loss from AP "
+                      "- sending probe request\n", sdata->dev->name);
 #endif
 
        ifmgd->flags |= IEEE80211_STA_PROBEREQ_POLL;
@@ -1320,10 +1136,13 @@ void ieee80211_beacon_loss_work(struct work_struct *work)
        ieee80211_recalc_ps(sdata->local, -1);
        mutex_unlock(&sdata->local->iflist_mtx);
 
-       ieee80211_send_probe_req(sdata, ifmgd->bssid, ifmgd->ssid,
-                                ifmgd->ssid_len, NULL, 0);
+       ssid = ieee80211_bss_get_ie(&ifmgd->associated->cbss, WLAN_EID_SSID);
+       ieee80211_send_probe_req(sdata, ifmgd->associated->cbss.bssid,
+                                ssid + 2, ssid[1], NULL, 0);
 
        mod_timer(&ifmgd->timer, jiffies + IEEE80211_PROBE_WAIT);
+ out:
+       mutex_unlock(&ifmgd->mtx);
 }
 
 void ieee80211_beacon_loss(struct ieee80211_vif *vif)
@@ -1335,105 +1154,16 @@ void ieee80211_beacon_loss(struct ieee80211_vif *vif)
 }
 EXPORT_SYMBOL(ieee80211_beacon_loss);
 
-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;
-       unsigned long last_rx;
-       bool disassoc = false;
-
-       /* TODO: start monitoring current AP signal quality and number of
-        * missed beacons. Scan other channels every now and then and search
-        * for better APs. */
-       /* TODO: remove expired BSSes */
-
-       ifmgd->state = IEEE80211_STA_MLME_ASSOCIATED;
-
-       rcu_read_lock();
-
-       sta = sta_info_get(local, ifmgd->bssid);
-       if (!sta) {
-               printk(KERN_DEBUG "%s: No STA entry for own AP %pM\n",
-                      sdata->dev->name, ifmgd->bssid);
-               disassoc = true;
-               rcu_read_unlock();
-               goto out;
-       }
-
-       last_rx = sta->last_rx;
-       rcu_read_unlock();
-
-       if ((ifmgd->flags & IEEE80211_STA_PROBEREQ_POLL) &&
-           time_after(jiffies, last_rx + IEEE80211_PROBE_WAIT)) {
-               printk(KERN_DEBUG "%s: no probe response from AP %pM "
-                      "- disassociating\n",
-                      sdata->dev->name, ifmgd->bssid);
-               disassoc = true;
-               ifmgd->flags &= ~IEEE80211_STA_PROBEREQ_POLL;
-               goto out;
-       }
-
-       /*
-        * Beacon filtering is only enabled with power save and then the
-        * stack should not check for beacon loss.
-        */
-       if (!((local->hw.flags & IEEE80211_HW_BEACON_FILTER) &&
-             (local->hw.conf.flags & IEEE80211_CONF_PS)) &&
-           time_after(jiffies,
-                      ifmgd->last_beacon + IEEE80211_MONITORING_INTERVAL)) {
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-               if (net_ratelimit()) {
-                       printk(KERN_DEBUG "%s: beacon loss from AP %pM "
-                              "- sending probe request\n",
-                              sdata->dev->name, ifmgd->bssid);
-               }
-#endif
-               ifmgd->flags |= IEEE80211_STA_PROBEREQ_POLL;
-               mutex_lock(&local->iflist_mtx);
-               ieee80211_recalc_ps(local, -1);
-               mutex_unlock(&local->iflist_mtx);
-               ieee80211_send_probe_req(sdata, ifmgd->bssid, ifmgd->ssid,
-                                        ifmgd->ssid_len, NULL, 0);
-               mod_timer(&ifmgd->timer, jiffies + IEEE80211_PROBE_WAIT);
-               goto out;
-       }
-
-       if (time_after(jiffies, last_rx + IEEE80211_PROBE_IDLE_TIME)) {
-               ifmgd->flags |= IEEE80211_STA_PROBEREQ_POLL;
-               mutex_lock(&local->iflist_mtx);
-               ieee80211_recalc_ps(local, -1);
-               mutex_unlock(&local->iflist_mtx);
-               ieee80211_send_probe_req(sdata, ifmgd->bssid, ifmgd->ssid,
-                                        ifmgd->ssid_len, NULL, 0);
-       }
-
- out:
-       if (!disassoc)
-               mod_timer(&ifmgd->timer,
-                         jiffies + IEEE80211_MONITORING_INTERVAL);
-       else
-               ieee80211_set_disassoc(sdata, true, true,
-                                       WLAN_REASON_PREV_AUTH_NOT_VALID);
-}
-
-
-static void ieee80211_auth_completed(struct ieee80211_sub_if_data *sdata)
+static void ieee80211_auth_completed(struct ieee80211_sub_if_data *sdata,
+                                    struct ieee80211_mgd_work *wk)
 {
-       struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
-
+       wk->state = IEEE80211_MGD_STATE_IDLE;
        printk(KERN_DEBUG "%s: authenticated\n", sdata->dev->name);
-       ifmgd->flags |= IEEE80211_STA_AUTHENTICATED;
-       if (ifmgd->flags & IEEE80211_STA_EXT_SME) {
-               /* Wait for SME to request association */
-               ifmgd->state = IEEE80211_STA_MLME_DISABLED;
-               ieee80211_recalc_idle(sdata->local);
-       } else
-               ieee80211_associate(sdata);
 }
 
 
 static void ieee80211_auth_challenge(struct ieee80211_sub_if_data *sdata,
+                                    struct ieee80211_mgd_work *wk,
                                     struct ieee80211_mgmt *mgmt,
                                     size_t len)
 {
@@ -1444,161 +1174,132 @@ 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, 3, sdata->u.mgd.auth_alg,
+       ieee80211_send_auth(sdata, 3, wk->auth_alg,
                            elems.challenge - 2, elems.challenge_len + 2,
-                           sdata->u.mgd.bssid, 1);
-       sdata->u.mgd.auth_transaction = 4;
+                           wk->bss->cbss.bssid, 1);
+       wk->auth_transaction = 4;
 }
 
-static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata,
-                                  struct ieee80211_mgmt *mgmt,
-                                  size_t len)
+static enum rx_mgmt_action __must_check
+ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata,
+                      struct ieee80211_mgd_work *wk,
+                      struct ieee80211_mgmt *mgmt, size_t len)
 {
-       struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
        u16 auth_alg, auth_transaction, status_code;
 
-       if (ifmgd->state != IEEE80211_STA_MLME_AUTHENTICATE)
-               return;
+       if (wk->state != IEEE80211_MGD_STATE_AUTH)
+               return RX_MGMT_NONE;
 
        if (len < 24 + 6)
-               return;
+               return RX_MGMT_NONE;
 
-       if (memcmp(ifmgd->bssid, mgmt->sa, ETH_ALEN) != 0)
-               return;
+       if (memcmp(wk->bss->cbss.bssid, mgmt->sa, ETH_ALEN) != 0)
+               return RX_MGMT_NONE;
 
-       if (memcmp(ifmgd->bssid, mgmt->bssid, ETH_ALEN) != 0)
-               return;
+       if (memcmp(wk->bss->cbss.bssid, mgmt->bssid, ETH_ALEN) != 0)
+               return RX_MGMT_NONE;
 
        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 != ifmgd->auth_alg ||
-           auth_transaction != ifmgd->auth_transaction)
-               return;
+       if (auth_alg != wk->auth_alg ||
+           auth_transaction != wk->auth_transaction)
+               return RX_MGMT_NONE;
 
        if (status_code != WLAN_STATUS_SUCCESS) {
-               if (status_code == WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG) {
-                       u8 algs[3];
-                       const int num_algs = ARRAY_SIZE(algs);
-                       int i, pos;
-                       algs[0] = algs[1] = algs[2] = 0xff;
-                       if (ifmgd->auth_algs & IEEE80211_AUTH_ALG_OPEN)
-                               algs[0] = WLAN_AUTH_OPEN;
-                       if (ifmgd->auth_algs & IEEE80211_AUTH_ALG_SHARED_KEY)
-                               algs[1] = WLAN_AUTH_SHARED_KEY;
-                       if (ifmgd->auth_algs & IEEE80211_AUTH_ALG_LEAP)
-                               algs[2] = WLAN_AUTH_LEAP;
-                       if (ifmgd->auth_alg == WLAN_AUTH_OPEN)
-                               pos = 0;
-                       else if (ifmgd->auth_alg == WLAN_AUTH_SHARED_KEY)
-                               pos = 1;
-                       else
-                               pos = 2;
-                       for (i = 0; i < num_algs; i++) {
-                               pos++;
-                               if (pos >= num_algs)
-                                       pos = 0;
-                               if (algs[pos] == ifmgd->auth_alg ||
-                                   algs[pos] == 0xff)
-                                       continue;
-                               if (algs[pos] == WLAN_AUTH_SHARED_KEY &&
-                                   !ieee80211_sta_wep_configured(sdata))
-                                       continue;
-                               ifmgd->auth_alg = algs[pos];
-                               break;
-                       }
-               }
-               return;
+               list_del(&wk->list);
+               kfree(wk);
+               return RX_MGMT_CFG80211_AUTH;
        }
 
-       switch (ifmgd->auth_alg) {
+       switch (wk->auth_alg) {
        case WLAN_AUTH_OPEN:
        case WLAN_AUTH_LEAP:
        case WLAN_AUTH_FT:
-               ieee80211_auth_completed(sdata);
-               cfg80211_send_rx_auth(sdata->dev, (u8 *) mgmt, len);
-               break;
+               ieee80211_auth_completed(sdata, wk);
+               return RX_MGMT_CFG80211_AUTH;
        case WLAN_AUTH_SHARED_KEY:
-               if (ifmgd->auth_transaction == 4) {
-                       ieee80211_auth_completed(sdata);
-                       cfg80211_send_rx_auth(sdata->dev, (u8 *) mgmt, len);
+               if (wk->auth_transaction == 4) {
+                       ieee80211_auth_completed(sdata, wk);
+                       return RX_MGMT_CFG80211_AUTH;
                } else
-                       ieee80211_auth_challenge(sdata, mgmt, len);
+                       ieee80211_auth_challenge(sdata, wk, mgmt, len);
                break;
        }
+
+       return RX_MGMT_NONE;
 }
 
 
-static void ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata,
-                                    struct ieee80211_mgmt *mgmt,
-                                    size_t len)
+static enum rx_mgmt_action __must_check
+ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata,
+                        struct ieee80211_mgd_work *wk,
+                        struct ieee80211_mgmt *mgmt, size_t len)
 {
        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+       const u8 *bssid = NULL;
        u16 reason_code;
 
        if (len < 24 + 2)
-               return;
+               return RX_MGMT_NONE;
 
-       if (memcmp(ifmgd->bssid, mgmt->sa, ETH_ALEN))
-               return;
+       ASSERT_MGD_MTX(ifmgd);
+
+       if (wk)
+               bssid = wk->bss->cbss.bssid;
+       else
+               bssid = ifmgd->associated->cbss.bssid;
 
        reason_code = le16_to_cpu(mgmt->u.deauth.reason_code);
 
-       if (ifmgd->flags & IEEE80211_STA_AUTHENTICATED)
-               printk(KERN_DEBUG "%s: deauthenticated (Reason: %u)\n",
-                               sdata->dev->name, reason_code);
+       printk(KERN_DEBUG "%s: deauthenticated from %pM (Reason: %u)\n",
+                       sdata->dev->name, bssid, reason_code);
 
-       if (!(ifmgd->flags & IEEE80211_STA_EXT_SME) &&
-           (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);
+       if (!wk) {
+               ieee80211_set_disassoc(sdata, bssid, true);
+       } else {
+               list_del(&wk->list);
+               kfree(wk);
        }
 
-       ieee80211_set_disassoc(sdata, true, false, 0);
-       ifmgd->flags &= ~IEEE80211_STA_AUTHENTICATED;
-       cfg80211_send_deauth(sdata->dev, (u8 *) mgmt, len);
+       return RX_MGMT_CFG80211_DEAUTH;
 }
 
 
-static void ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata,
-                                      struct ieee80211_mgmt *mgmt,
-                                      size_t len)
+static enum rx_mgmt_action __must_check
+ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata,
+                          struct ieee80211_mgmt *mgmt, size_t len)
 {
        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
        u16 reason_code;
 
        if (len < 24 + 2)
-               return;
+               return RX_MGMT_NONE;
 
-       if (memcmp(ifmgd->bssid, mgmt->sa, ETH_ALEN))
-               return;
+       ASSERT_MGD_MTX(ifmgd);
 
-       reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code);
+       if (WARN_ON(!ifmgd->associated))
+               return RX_MGMT_NONE;
 
-       if (ifmgd->flags & IEEE80211_STA_ASSOCIATED)
-               printk(KERN_DEBUG "%s: disassociated (Reason: %u)\n",
-                               sdata->dev->name, reason_code);
+       if (WARN_ON(memcmp(ifmgd->associated->cbss.bssid, mgmt->sa, ETH_ALEN)))
+               return RX_MGMT_NONE;
 
-       if (!(ifmgd->flags & IEEE80211_STA_EXT_SME) &&
-           ifmgd->state == IEEE80211_STA_MLME_ASSOCIATED) {
-               ifmgd->state = IEEE80211_STA_MLME_ASSOCIATE;
-               mod_timer(&ifmgd->timer, jiffies +
-                                     IEEE80211_RETRY_AUTH_INTERVAL);
-       }
+       reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code);
+
+       printk(KERN_DEBUG "%s: disassociated (Reason: %u)\n",
+                       sdata->dev->name, reason_code);
 
-       ieee80211_set_disassoc(sdata, false, false, reason_code);
-       cfg80211_send_disassoc(sdata->dev, (u8 *) mgmt, len);
+       ieee80211_set_disassoc(sdata, ifmgd->associated->cbss.bssid, false);
+       return RX_MGMT_CFG80211_DISASSOC;
 }
 
 
-static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
-                                        struct ieee80211_mgmt *mgmt,
-                                        size_t len,
-                                        int reassoc)
+static enum rx_mgmt_action __must_check
+ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
+                            struct ieee80211_mgd_work *wk,
+                            struct ieee80211_mgmt *mgmt, size_t len,
+                            bool reassoc)
 {
        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
        struct ieee80211_local *local = sdata->local;
@@ -1614,17 +1315,16 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
        bool have_higher_than_11mbit = false, newsta = false;
        u16 ap_ht_cap_flags;
 
-       /* AssocResp and ReassocResp have identical structure, so process both
-        * of them in this function. */
-
-       if (ifmgd->state != IEEE80211_STA_MLME_ASSOCIATE)
-               return;
+       /*
+        * AssocResp and ReassocResp have identical structure, so process both
+        * of them in this function.
+        */
 
        if (len < 24 + 6)
-               return;
+               return RX_MGMT_NONE;
 
-       if (memcmp(ifmgd->bssid, mgmt->sa, ETH_ALEN) != 0)
-               return;
+       if (memcmp(wk->bss->cbss.bssid, mgmt->sa, ETH_ALEN) != 0)
+               return RX_MGMT_NONE;
 
        capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info);
        status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code);
@@ -1647,26 +1347,19 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
                printk(KERN_DEBUG "%s: AP rejected association temporarily; "
                       "comeback duration %u TU (%u ms)\n",
                       sdata->dev->name, tu, ms);
+               wk->timeout = jiffies + msecs_to_jiffies(ms);
                if (ms > IEEE80211_ASSOC_TIMEOUT)
                        mod_timer(&ifmgd->timer,
                                  jiffies + msecs_to_jiffies(ms));
-               return;
+               return RX_MGMT_NONE;
        }
 
        if (status_code != WLAN_STATUS_SUCCESS) {
                printk(KERN_DEBUG "%s: AP denied association (code=%d)\n",
                       sdata->dev->name, status_code);
-               /* 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. */
-               ifmgd->flags &= ~IEEE80211_STA_PREV_BSSID_SET;
-               cfg80211_send_rx_assoc(sdata->dev, (u8 *) mgmt, len);
-               if (ifmgd->flags & IEEE80211_STA_EXT_SME) {
-                       /* Wait for SME to decide what to do next */
-                       ifmgd->state = IEEE80211_STA_MLME_DISABLED;
-                       ieee80211_recalc_idle(local);
-               }
-               return;
+               list_del(&wk->list);
+               kfree(wk);
+               return RX_MGMT_CFG80211_ASSOC;
        }
 
        if ((aid & (BIT(15) | BIT(14))) != (BIT(15) | BIT(14)))
@@ -1677,51 +1370,38 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
        if (!elems.supp_rates) {
                printk(KERN_DEBUG "%s: no SuppRates element in AssocResp\n",
                       sdata->dev->name);
-               return;
+               return RX_MGMT_NONE;
        }
 
        printk(KERN_DEBUG "%s: associated\n", sdata->dev->name);
        ifmgd->aid = aid;
-       ifmgd->ap_capab = capab_info;
-
-       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, ifmgd->bssid);
+       sta = sta_info_get(local, wk->bss->cbss.bssid);
        if (!sta) {
                newsta = true;
 
-               sta = sta_info_alloc(sdata, ifmgd->bssid, GFP_ATOMIC);
+               rcu_read_unlock();
+
+               sta = sta_info_alloc(sdata, wk->bss->cbss.bssid, GFP_KERNEL);
                if (!sta) {
                        printk(KERN_DEBUG "%s: failed to alloc STA entry for"
                               " the AP\n", sdata->dev->name);
-                       rcu_read_unlock();
-                       return;
+                       return RX_MGMT_NONE;
                }
 
                /* update new sta with its last rx activity */
                sta->last_rx = jiffies;
-       }
 
-       /*
-        * FIXME: Do we really need to update the sta_info's information here?
-        *        We already know about the AP (we found it in our list) so it
-        *        should already be filled with the right info, no?
-        *        As is stands, all this is racy because typically we assume
-        *        the information that is filled in here (except flags) doesn't
-        *        change while a STA structure is alive. As such, it should move
-        *        to between the sta_info_alloc() and sta_info_insert() above.
-        */
+               set_sta_flags(sta, WLAN_STA_AUTH | WLAN_STA_ASSOC |
+                                  WLAN_STA_ASSOC_AP);
+               if (!(ifmgd->flags & IEEE80211_STA_CONTROL_PORT))
+                       set_sta_flags(sta, WLAN_STA_AUTHORIZED);
 
-       set_sta_flags(sta, WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_ASSOC_AP);
-       if (!(ifmgd->flags & IEEE80211_STA_CONTROL_PORT))
-               set_sta_flags(sta, WLAN_STA_AUTHORIZED);
+               rcu_read_lock();
+       }
 
        rates = 0;
        basic_rates = 0;
@@ -1771,8 +1451,7 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
        else
                sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE;
 
-       /* 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))
+       if (elems.ht_cap_elem && !(ifmgd->flags & IEEE80211_STA_DISABLE_11N))
                ieee80211_ht_cap_ie_to_sta_ht_cap(sband,
                                elems.ht_cap_elem, &sta->sta.ht_cap);
 
@@ -1792,7 +1471,7 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
                        printk(KERN_DEBUG "%s: failed to insert STA entry for"
                               " the AP (error %d)\n", sdata->dev->name, err);
                        rcu_read_unlock();
-                       return;
+                       return RX_MGMT_NONE;
                }
        }
 
@@ -1806,15 +1485,16 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
 
        if (elems.ht_info_elem && elems.wmm_param &&
            (ifmgd->flags & IEEE80211_STA_WMM_ENABLED) &&
-           !(ifmgd->flags & IEEE80211_STA_TKIP_WEP_USED))
+           !(ifmgd->flags & IEEE80211_STA_DISABLE_11N))
                changed |= ieee80211_enable_ht(sdata, elems.ht_info_elem,
+                                              wk->bss->cbss.bssid,
                                               ap_ht_cap_flags);
 
        /* set AID and assoc capability,
         * ieee80211_set_associated() will tell the driver */
        bss_conf->aid = aid;
        bss_conf->assoc_capability = capab_info;
-       ieee80211_set_associated(sdata, changed);
+       ieee80211_set_associated(sdata, wk->bss, changed);
 
        /*
         * initialise the time of last beacon to be the association time,
@@ -1822,8 +1502,9 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
         */
        ifmgd->last_beacon = jiffies;
 
-       ieee80211_associated(sdata);
-       cfg80211_send_rx_assoc(sdata->dev, (u8 *) mgmt, len);
+       list_del(&wk->list);
+       kfree(wk);
+       return RX_MGMT_CFG80211_ASSOC;
 }
 
 
@@ -1851,23 +1532,25 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
 
        bss = ieee80211_bss_info_update(local, rx_status, mgmt, len, elems,
                                        channel, beacon);
-       if (!bss)
+       if (bss)
+               ieee80211_rx_bss_put(local, bss);
+
+       if (!sdata->u.mgd.associated)
                return;
 
        if (elems->ch_switch_elem && (elems->ch_switch_elem_len == 3) &&
-           (memcmp(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN) == 0)) {
+           (memcmp(mgmt->bssid, sdata->u.mgd.associated->cbss.bssid,
+                                                       ETH_ALEN) == 0)) {
                struct ieee80211_channel_sw_ie *sw_elem =
                        (struct ieee80211_channel_sw_ie *)elems->ch_switch_elem;
                ieee80211_sta_process_chanswitch(sdata, sw_elem, bss);
        }
-
-       ieee80211_rx_bss_put(local, bss);
 }
 
 
 static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata,
-                                        struct ieee80211_mgmt *mgmt,
-                                        size_t len,
+                                        struct ieee80211_mgd_work *wk,
+                                        struct ieee80211_mgmt *mgmt, size_t len,
                                         struct ieee80211_rx_status *rx_status)
 {
        struct ieee80211_if_managed *ifmgd;
@@ -1876,6 +1559,8 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata,
 
        ifmgd = &sdata->u.mgd;
 
+       ASSERT_MGD_MTX(ifmgd);
+
        if (memcmp(mgmt->da, sdata->dev->dev_addr, ETH_ALEN))
                return; /* ignore ProbeResp to foreign address */
 
@@ -1889,13 +1574,17 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata,
        ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, false);
 
        /* direct probe may be part of the association flow */
-       if (ifmgd->state == IEEE80211_STA_MLME_DIRECT_PROBE) {
+       if (wk && wk->state == IEEE80211_MGD_STATE_PROBE) {
                printk(KERN_DEBUG "%s direct probe responded\n",
                       sdata->dev->name);
-               ieee80211_authenticate(sdata);
+               wk->tries = 0;
+               wk->state = IEEE80211_MGD_STATE_AUTH;
+               WARN_ON(ieee80211_authenticate(sdata, wk) != RX_MGMT_NONE);
        }
 
-       if (ifmgd->flags & IEEE80211_STA_PROBEREQ_POLL) {
+       if (ifmgd->associated &&
+           memcmp(mgmt->bssid, ifmgd->associated->cbss.bssid, ETH_ALEN) == 0 &&
+           ifmgd->flags & IEEE80211_STA_PROBEREQ_POLL) {
                ifmgd->flags &= ~IEEE80211_STA_PROBEREQ_POLL;
                mutex_lock(&sdata->local->iflist_mtx);
                ieee80211_recalc_ps(sdata->local, -1);
@@ -1937,6 +1626,9 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
        bool erp_valid, directed_tim = false;
        u8 erp_value = 0;
        u32 ncrc;
+       u8 *bssid;
+
+       ASSERT_MGD_MTX(ifmgd);
 
        /* Process beacon from the current BSS */
        baselen = (u8 *) mgmt->u.beacon.variable - (u8 *) mgmt;
@@ -1946,8 +1638,12 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
        if (rx_status->freq != local->hw.conf.channel->center_freq)
                return;
 
-       if (!(ifmgd->flags & IEEE80211_STA_ASSOCIATED) ||
-           memcmp(ifmgd->bssid, mgmt->bssid, ETH_ALEN) != 0)
+       if (WARN_ON(!ifmgd->associated))
+               return;
+
+       bssid = ifmgd->associated->cbss.bssid;
+
+       if (WARN_ON(memcmp(bssid, mgmt->bssid, ETH_ALEN) != 0))
                return;
 
        if (ifmgd->flags & IEEE80211_STA_PROBEREQ_POLL) {
@@ -2019,15 +1715,15 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
 
 
        if (elems.ht_cap_elem && elems.ht_info_elem && elems.wmm_param &&
-           !(ifmgd->flags & IEEE80211_STA_TKIP_WEP_USED)) {
+           !(ifmgd->flags & IEEE80211_STA_DISABLE_11N)) {
                struct sta_info *sta;
                struct ieee80211_supported_band *sband;
                u16 ap_ht_cap_flags;
 
                rcu_read_lock();
 
-               sta = sta_info_get(local, ifmgd->bssid);
-               if (!sta) {
+               sta = sta_info_get(local, bssid);
+               if (WARN_ON(!sta)) {
                        rcu_read_unlock();
                        return;
                }
@@ -2042,7 +1738,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
                rcu_read_unlock();
 
                changed |= ieee80211_enable_ht(sdata, elems.ht_info_elem,
-                                              ap_ht_cap_flags);
+                                              bssid, ap_ht_cap_flags);
        }
 
        if (elems.country_elem) {
@@ -2063,8 +1759,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
 }
 
 ieee80211_rx_result ieee80211_sta_rx_mgmt(struct ieee80211_sub_if_data *sdata,
-                                         struct sk_buff *skb,
-                                         struct ieee80211_rx_status *rx_status)
+                                         struct sk_buff *skb)
 {
        struct ieee80211_local *local = sdata->local;
        struct ieee80211_mgmt *mgmt;
@@ -2080,12 +1775,12 @@ ieee80211_rx_result ieee80211_sta_rx_mgmt(struct ieee80211_sub_if_data *sdata,
        case IEEE80211_STYPE_PROBE_REQ:
        case IEEE80211_STYPE_PROBE_RESP:
        case IEEE80211_STYPE_BEACON:
-               memcpy(skb->cb, rx_status, sizeof(*rx_status));
        case IEEE80211_STYPE_AUTH:
        case IEEE80211_STYPE_ASSOC_RESP:
        case IEEE80211_STYPE_REASSOC_RESP:
        case IEEE80211_STYPE_DEAUTH:
        case IEEE80211_STYPE_DISASSOC:
+       case IEEE80211_STYPE_ACTION:
                skb_queue_tail(&sdata->u.mgd.skb_queue, skb);
                queue_work(local->hw.workqueue, &sdata->u.mgd.work);
                return RX_QUEUED;
@@ -2097,40 +1792,116 @@ ieee80211_rx_result ieee80211_sta_rx_mgmt(struct ieee80211_sub_if_data *sdata,
 static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
                                         struct sk_buff *skb)
 {
+       struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
        struct ieee80211_rx_status *rx_status;
        struct ieee80211_mgmt *mgmt;
+       struct ieee80211_mgd_work *wk;
+       enum rx_mgmt_action rma = RX_MGMT_NONE;
        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_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);
+       mutex_lock(&ifmgd->mtx);
+
+       if (ifmgd->associated &&
+           memcmp(ifmgd->associated->cbss.bssid, mgmt->bssid,
+                                                       ETH_ALEN) == 0) {
+               switch (fc & IEEE80211_FCTL_STYPE) {
+               case IEEE80211_STYPE_BEACON:
+                       ieee80211_rx_mgmt_beacon(sdata, mgmt, skb->len,
+                                                rx_status);
+                       break;
+               case IEEE80211_STYPE_PROBE_RESP:
+                       ieee80211_rx_mgmt_probe_resp(sdata, NULL, mgmt,
+                                                    skb->len, rx_status);
+                       break;
+               case IEEE80211_STYPE_DEAUTH:
+                       rma = ieee80211_rx_mgmt_deauth(sdata, NULL,
+                                                      mgmt, skb->len);
+                       break;
+               case IEEE80211_STYPE_DISASSOC:
+                       rma = ieee80211_rx_mgmt_disassoc(sdata, mgmt, skb->len);
+                       break;
+               case IEEE80211_STYPE_ACTION:
+                       /* XXX: differentiate, can only happen for CSA now! */
+                       ieee80211_sta_process_chanswitch(sdata,
+                                       &mgmt->u.action.u.chan_switch.sw_elem,
+                                       ifmgd->associated);
+                       break;
+               }
+               mutex_unlock(&ifmgd->mtx);
+
+               switch (rma) {
+               case RX_MGMT_NONE:
+                       /* no action */
+                       break;
+               case RX_MGMT_CFG80211_DEAUTH:
+                       cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, skb->len,
+                                            NULL);
+                       break;
+               case RX_MGMT_CFG80211_DISASSOC:
+                       cfg80211_send_disassoc(sdata->dev, (u8 *)mgmt, skb->len,
+                                              NULL);
+                       break;
+               default:
+                       WARN(1, "unexpected: %d", rma);
+               }
+               goto out;
+       }
+
+       list_for_each_entry(wk, &ifmgd->work_list, list) {
+               if (memcmp(wk->bss->cbss.bssid, mgmt->bssid, ETH_ALEN) != 0)
+                       continue;
+
+               switch (fc & IEEE80211_FCTL_STYPE) {
+               case IEEE80211_STYPE_PROBE_RESP:
+                       ieee80211_rx_mgmt_probe_resp(sdata, wk, mgmt, skb->len,
+                                                    rx_status);
+                       break;
+               case IEEE80211_STYPE_AUTH:
+                       rma = ieee80211_rx_mgmt_auth(sdata, wk, mgmt, skb->len);
+                       break;
+               case IEEE80211_STYPE_ASSOC_RESP:
+                       rma = ieee80211_rx_mgmt_assoc_resp(sdata, wk, mgmt,
+                                                          skb->len, false);
+                       break;
+               case IEEE80211_STYPE_REASSOC_RESP:
+                       rma = ieee80211_rx_mgmt_assoc_resp(sdata, wk, mgmt,
+                                                          skb->len, true);
+                       break;
+               case IEEE80211_STYPE_DEAUTH:
+                       rma = ieee80211_rx_mgmt_deauth(sdata, wk, mgmt,
+                                                      skb->len);
+                       break;
+               }
+               /*
+                * We've processed this frame for that work, so it can't
+                * belong to another work struct.
+                * NB: this is also required for correctness because the
+                * called functions can free 'wk', and for 'rma'!
+                */
                break;
-       case IEEE80211_STYPE_REASSOC_RESP:
-               ieee80211_rx_mgmt_assoc_resp(sdata, mgmt, skb->len, 1);
+       }
+
+       mutex_unlock(&ifmgd->mtx);
+
+       switch (rma) {
+       case RX_MGMT_NONE:
+               /* no action */
                break;
-       case IEEE80211_STYPE_DEAUTH:
-               ieee80211_rx_mgmt_deauth(sdata, mgmt, skb->len);
+       case RX_MGMT_CFG80211_AUTH:
+               cfg80211_send_rx_auth(sdata->dev, (u8 *) mgmt, skb->len);
                break;
-       case IEEE80211_STYPE_DISASSOC:
-               ieee80211_rx_mgmt_disassoc(sdata, mgmt, skb->len);
+       case RX_MGMT_CFG80211_ASSOC:
+               cfg80211_send_rx_assoc(sdata->dev, (u8 *) mgmt, skb->len);
                break;
+       default:
+               WARN(1, "unexpected: %d", rma);
        }
 
+ out:
        kfree_skb(skb);
 }
 
@@ -2146,125 +1917,9 @@ static void ieee80211_sta_timer(unsigned long data)
                return;
        }
 
-       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_managed *ifmgd = &sdata->u.mgd;
-       struct ieee80211_local *local = sdata->local;
-
-       /* Reset own TSF to allow time synchronization work. */
-       drv_reset_tsf(local);
-
-       ifmgd->wmm_last_param_set = -1; /* allow any WMM update */
-
-
-       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 if (ifmgd->auth_algs & IEEE80211_AUTH_ALG_FT)
-               ifmgd->auth_alg = WLAN_AUTH_FT;
-       else
-               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_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 = 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 (!(ifmgd->flags & IEEE80211_STA_EXT_SME) &&
-           ifmgd->flags & (IEEE80211_STA_AUTO_SSID_SEL |
-                           IEEE80211_STA_AUTO_BSSID_SEL |
-                           IEEE80211_STA_AUTO_CHANNEL_SEL)) {
-               capa_mask |= WLAN_CAPABILITY_PRIVACY;
-               if (sdata->default_key)
-                       capa_val |= WLAN_CAPABILITY_PRIVACY;
-       }
-
-       if (ifmgd->flags & IEEE80211_STA_AUTO_CHANNEL_SEL)
-               chan = NULL;
-
-       if (ifmgd->flags & IEEE80211_STA_AUTO_BSSID_SEL)
-               bssid = NULL;
-
-       if (ifmgd->flags & IEEE80211_STA_AUTO_SSID_SEL) {
-               ssid = NULL;
-               ssid_len = 0;
-       }
-
-       bss = (void *)cfg80211_get_bss(local->hw.wiphy, chan,
-                                      bssid, ssid, ssid_len,
-                                      capa_mask, capa_val);
-
-       if (bss) {
-               local->oper_channel = bss->cbss.channel;
-               local->oper_channel_type = NL80211_CHAN_NO_HT;
-               ieee80211_hw_config(local, 0);
-
-               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.mgd.mfp == IEEE80211_MFP_REQUIRED)
-                       sdata->u.mgd.flags |= IEEE80211_STA_MFP_ENABLED;
-               else
-                       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
-                */
-               if (!bss->last_probe_resp ||
-                   time_after(jiffies, bss->last_probe_resp
-                                       + IEEE80211_SCAN_RESULT_EXPIRE))
-                       ifmgd->state = IEEE80211_STA_MLME_DIRECT_PROBE;
-               else
-                       ifmgd->state = IEEE80211_STA_MLME_AUTHENTICATE;
-
-               ieee80211_rx_bss_put(local, bss);
-               ieee80211_sta_reset_auth(sdata);
-               return 0;
-       } else {
-               if (ifmgd->assoc_scan_tries < IEEE80211_ASSOC_SCANS_MAX_TRIES) {
-
-                       ifmgd->assoc_scan_tries++;
-
-                       ieee80211_request_internal_scan(sdata, ifmgd->ssid,
-                                                       ssid_len);
-
-                       ifmgd->state = IEEE80211_STA_MLME_AUTHENTICATE;
-                       set_bit(IEEE80211_STA_REQ_AUTH, &ifmgd->request);
-               } else {
-                       ifmgd->assoc_scan_tries = 0;
-                       ifmgd->state = IEEE80211_STA_MLME_DISABLED;
-                       ieee80211_recalc_idle(local);
-               }
-       }
-       return -1;
-}
-
-
 static void ieee80211_sta_work(struct work_struct *work)
 {
        struct ieee80211_sub_if_data *sdata =
@@ -2272,6 +1927,10 @@ static void ieee80211_sta_work(struct work_struct *work)
        struct ieee80211_local *local = sdata->local;
        struct ieee80211_if_managed *ifmgd;
        struct sk_buff *skb;
+       struct ieee80211_mgd_work *wk, *tmp;
+       LIST_HEAD(free_work);
+       enum rx_mgmt_action rma;
+       bool anybusy = false;
 
        if (!netif_running(sdata->dev))
                return;
@@ -2294,54 +1953,91 @@ static void ieee80211_sta_work(struct work_struct *work)
 
        ifmgd = &sdata->u.mgd;
 
+       /* first process frames to avoid timing out while a frame is pending */
        while ((skb = skb_dequeue(&ifmgd->skb_queue)))
                ieee80211_sta_rx_queued_mgmt(sdata, skb);
 
-       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)) {
-               queue_delayed_work(local->hw.workqueue, &local->scan_work,
-                                  round_jiffies_relative(0));
-               return;
+       /* then process the rest of the work */
+       mutex_lock(&ifmgd->mtx);
+
+       list_for_each_entry(wk, &ifmgd->work_list, list) {
+               if (wk->state != IEEE80211_MGD_STATE_IDLE) {
+                       anybusy = true;
+                       break;
+               }
        }
 
-       if (test_and_clear_bit(IEEE80211_STA_REQ_AUTH, &ifmgd->request)) {
-               if (ieee80211_sta_config_auth(sdata))
-                       return;
-               clear_bit(IEEE80211_STA_REQ_RUN, &ifmgd->request);
-       } else if (!test_and_clear_bit(IEEE80211_STA_REQ_RUN, &ifmgd->request))
+       ieee80211_recalc_idle(local);
+
+       if (!anybusy) {
+               mutex_unlock(&ifmgd->mtx);
+
+               if (test_and_clear_bit(IEEE80211_STA_REQ_SCAN, &ifmgd->request))
+                       queue_delayed_work(local->hw.workqueue,
+                                          &local->scan_work,
+                                          round_jiffies_relative(0));
                return;
+       }
 
-       ieee80211_recalc_idle(local);
+       list_for_each_entry_safe(wk, tmp, &ifmgd->work_list, list) {
+               if (time_before(jiffies, wk->timeout))
+                       continue;
 
-       switch (ifmgd->state) {
-       case IEEE80211_STA_MLME_DISABLED:
-               break;
-       case IEEE80211_STA_MLME_DIRECT_PROBE:
-               ieee80211_direct_probe(sdata);
-               break;
-       case IEEE80211_STA_MLME_AUTHENTICATE:
-               ieee80211_authenticate(sdata);
-               break;
-       case IEEE80211_STA_MLME_ASSOCIATE:
-               ieee80211_associate(sdata);
-               break;
-       case IEEE80211_STA_MLME_ASSOCIATED:
-               ieee80211_associated(sdata);
-               break;
-       default:
-               WARN_ON(1);
-               break;
+               switch (wk->state) {
+               default:
+                       WARN_ON(1);
+                       /* fall through */
+               case IEEE80211_MGD_STATE_IDLE:
+                       /* nothing */
+                       rma = RX_MGMT_NONE;
+                       break;
+               case IEEE80211_MGD_STATE_PROBE:
+                       rma = ieee80211_direct_probe(sdata, wk);
+                       break;
+               case IEEE80211_MGD_STATE_AUTH:
+                       rma = ieee80211_authenticate(sdata, wk);
+                       break;
+               case IEEE80211_MGD_STATE_ASSOC:
+                       rma = ieee80211_associate(sdata, wk);
+                       break;
+               }
+
+               switch (rma) {
+               case RX_MGMT_NONE:
+                       /* no action required */
+                       break;
+               case RX_MGMT_CFG80211_AUTH_TO:
+               case RX_MGMT_CFG80211_ASSOC_TO:
+                       list_del(&wk->list);
+                       list_add(&wk->list, &free_work);
+                       wk->tries = rma; /* small abuse but only local */
+                       break;
+               default:
+                       WARN(1, "unexpected: %d", rma);
+               }
        }
 
-       if (ieee80211_privacy_mismatch(sdata)) {
-               printk(KERN_DEBUG "%s: privacy configuration mismatch and "
-                      "mixed-cell disabled - disassociate\n", sdata->dev->name);
+       mutex_unlock(&ifmgd->mtx);
 
-               ieee80211_set_disassoc(sdata, false, true,
-                                       WLAN_REASON_UNSPECIFIED);
+       list_for_each_entry_safe(wk, tmp, &free_work, list) {
+               switch (wk->tries) {
+               case RX_MGMT_CFG80211_AUTH_TO:
+                       cfg80211_send_auth_timeout(sdata->dev,
+                                                  wk->bss->cbss.bssid);
+                       break;
+               case RX_MGMT_CFG80211_ASSOC_TO:
+                       cfg80211_send_assoc_timeout(sdata->dev,
+                                                   wk->bss->cbss.bssid);
+                       break;
+               default:
+                       WARN(1, "unexpected: %d", wk->tries);
+               }
+
+               list_del(&wk->list);
+               kfree(wk);
        }
+
+       ieee80211_recalc_idle(local);
 }
 
 static void ieee80211_restart_sta_timer(struct ieee80211_sub_if_data *sdata)
@@ -2353,7 +2049,6 @@ static void ieee80211_restart_sta_timer(struct ieee80211_sub_if_data *sdata)
                 */
                sdata->u.mgd.last_beacon = jiffies;
 
-
                queue_work(sdata->local->hw.workqueue,
                           &sdata->u.mgd.work);
        }
@@ -2395,7 +2090,6 @@ void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata)
 void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata)
 {
        struct ieee80211_if_managed *ifmgd;
-       u32 hw_flags;
 
        ifmgd = &sdata->u.mgd;
        INIT_WORK(&ifmgd->work, ieee80211_sta_work);
@@ -2407,198 +2101,243 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata)
                    (unsigned long) sdata);
        skb_queue_head_init(&ifmgd->skb_queue);
 
+       INIT_LIST_HEAD(&ifmgd->work_list);
+
        ifmgd->capab = WLAN_CAPABILITY_ESS;
-       ifmgd->auth_algs = IEEE80211_AUTH_ALG_OPEN |
-               IEEE80211_AUTH_ALG_SHARED_KEY;
-       ifmgd->flags |= IEEE80211_STA_CREATE_IBSS |
-               IEEE80211_STA_AUTO_BSSID_SEL |
-               IEEE80211_STA_AUTO_CHANNEL_SEL;
+       ifmgd->flags = 0;
        if (sdata->local->hw.queues >= 4)
                ifmgd->flags |= IEEE80211_STA_WMM_ENABLED;
 
-       hw_flags = sdata->local->hw.flags;
-
-       if (hw_flags & IEEE80211_HW_SUPPORTS_PS) {
-               ifmgd->powersave = CONFIG_MAC80211_DEFAULT_PS_VALUE;
-               sdata->local->hw.conf.dynamic_ps_timeout = 500;
-       }
+       mutex_init(&ifmgd->mtx);
 }
 
-/* configuration hooks */
-void ieee80211_sta_req_auth(struct ieee80211_sub_if_data *sdata)
+/* scan finished notification */
+void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local)
 {
-       struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
-       struct ieee80211_local *local = sdata->local;
-
-       if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION))
-               return;
-
-       if ((ifmgd->flags & (IEEE80211_STA_BSSID_SET |
-                            IEEE80211_STA_AUTO_BSSID_SEL)) &&
-           (ifmgd->flags & (IEEE80211_STA_SSID_SET |
-                            IEEE80211_STA_AUTO_SSID_SEL))) {
-
-               if (ifmgd->state == IEEE80211_STA_MLME_ASSOCIATED)
-                       ieee80211_set_disassoc(sdata, true, true,
-                                              WLAN_REASON_DEAUTH_LEAVING);
-
-               if (ifmgd->ssid_len == 0) {
-                       /*
-                        * Only allow association to be started if a valid SSID
-                        * is configured.
-                        */
-                       return;
-               }
+       struct ieee80211_sub_if_data *sdata = local->scan_sdata;
 
-               if (!(ifmgd->flags & IEEE80211_STA_EXT_SME) ||
-                   ifmgd->state != IEEE80211_STA_MLME_ASSOCIATE)
-                       set_bit(IEEE80211_STA_REQ_AUTH, &ifmgd->request);
-               else if (ifmgd->flags & IEEE80211_STA_EXT_SME)
-                       set_bit(IEEE80211_STA_REQ_RUN, &ifmgd->request);
-               queue_work(local->hw.workqueue, &ifmgd->work);
-       }
+       /* Restart STA timers */
+       rcu_read_lock();
+       list_for_each_entry_rcu(sdata, &local->interfaces, list)
+               ieee80211_restart_sta_timer(sdata);
+       rcu_read_unlock();
 }
 
-int ieee80211_sta_commit(struct ieee80211_sub_if_data *sdata)
+int ieee80211_max_network_latency(struct notifier_block *nb,
+                                 unsigned long data, void *dummy)
 {
-       struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+       s32 latency_usec = (s32) data;
+       struct ieee80211_local *local =
+               container_of(nb, struct ieee80211_local,
+                            network_latency_notifier);
 
-       if (ifmgd->ssid_len)
-               ifmgd->flags |= IEEE80211_STA_SSID_SET;
-       else
-               ifmgd->flags &= ~IEEE80211_STA_SSID_SET;
+       mutex_lock(&local->iflist_mtx);
+       ieee80211_recalc_ps(local, latency_usec);
+       mutex_unlock(&local->iflist_mtx);
 
        return 0;
 }
 
-int ieee80211_sta_set_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size_t len)
+/* config hooks */
+int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
+                      struct cfg80211_auth_request *req)
 {
-       struct ieee80211_if_managed *ifmgd;
+       struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+       const u8 *ssid;
+       struct ieee80211_mgd_work *wk;
+       u16 auth_alg;
 
-       if (len > IEEE80211_MAX_SSID_LEN)
-               return -EINVAL;
+       switch (req->auth_type) {
+       case NL80211_AUTHTYPE_OPEN_SYSTEM:
+               auth_alg = WLAN_AUTH_OPEN;
+               break;
+       case NL80211_AUTHTYPE_SHARED_KEY:
+               auth_alg = WLAN_AUTH_SHARED_KEY;
+               break;
+       case NL80211_AUTHTYPE_FT:
+               auth_alg = WLAN_AUTH_FT;
+               break;
+       case NL80211_AUTHTYPE_NETWORK_EAP:
+               auth_alg = WLAN_AUTH_LEAP;
+               break;
+       default:
+               return -EOPNOTSUPP;
+       }
 
-       ifmgd = &sdata->u.mgd;
+       wk = kzalloc(sizeof(*wk) + req->ie_len, GFP_KERNEL);
+       if (!wk)
+               return -ENOMEM;
 
-       if (ifmgd->ssid_len != len || memcmp(ifmgd->ssid, ssid, len) != 0) {
-               if (ifmgd->state == IEEE80211_STA_MLME_ASSOCIATED)
-                       ieee80211_set_disassoc(sdata, true, true,
-                                              WLAN_REASON_DEAUTH_LEAVING);
+       wk->bss = (void *)req->bss;
 
-               /*
-                * Do not use reassociation if SSID is changed (different ESS).
-                */
-               ifmgd->flags &= ~IEEE80211_STA_PREV_BSSID_SET;
-               memset(ifmgd->ssid, 0, sizeof(ifmgd->ssid));
-               memcpy(ifmgd->ssid, ssid, len);
-               ifmgd->ssid_len = len;
+       if (req->ie && req->ie_len) {
+               memcpy(wk->ie, req->ie, req->ie_len);
+               wk->ie_len = req->ie_len;
        }
 
-       return ieee80211_sta_commit(sdata);
-}
+       ssid = ieee80211_bss_get_ie(req->bss, WLAN_EID_SSID);
+       memcpy(wk->ssid, ssid + 2, ssid[1]);
+       wk->ssid_len = ssid[1];
 
-int ieee80211_sta_get_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size_t *len)
-{
-       struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
-       memcpy(ssid, ifmgd->ssid, ifmgd->ssid_len);
-       *len = ifmgd->ssid_len;
+       wk->state = IEEE80211_MGD_STATE_PROBE;
+       wk->auth_alg = auth_alg;
+
+       /*
+        * XXX: if still associated need to tell AP that we're going
+        *      to sleep and then change channel etc.
+        */
+       sdata->local->oper_channel = req->bss->channel;
+       ieee80211_hw_config(sdata->local, 0);
+
+       mutex_lock(&ifmgd->mtx);
+       list_add(&wk->list, &sdata->u.mgd.work_list);
+       mutex_unlock(&ifmgd->mtx);
+
+       queue_work(sdata->local->hw.workqueue, &sdata->u.mgd.work);
        return 0;
 }
 
-int ieee80211_sta_set_bssid(struct ieee80211_sub_if_data *sdata, u8 *bssid)
+int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
+                       struct cfg80211_assoc_request *req)
 {
        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+       struct ieee80211_mgd_work *wk, *found = NULL;
+       int i, err;
 
-       if (compare_ether_addr(bssid, ifmgd->bssid) != 0 &&
-           ifmgd->state == IEEE80211_STA_MLME_ASSOCIATED)
-               ieee80211_set_disassoc(sdata, true, true,
-                                      WLAN_REASON_DEAUTH_LEAVING);
+       mutex_lock(&ifmgd->mtx);
 
-       if (is_valid_ether_addr(bssid)) {
-               memcpy(ifmgd->bssid, bssid, ETH_ALEN);
-               ifmgd->flags |= IEEE80211_STA_BSSID_SET;
-       } else {
-               memset(ifmgd->bssid, 0, ETH_ALEN);
-               ifmgd->flags &= ~IEEE80211_STA_BSSID_SET;
+       list_for_each_entry(wk, &ifmgd->work_list, list) {
+               if (&wk->bss->cbss == req->bss &&
+                   wk->state == IEEE80211_MGD_STATE_IDLE) {
+                       found = wk;
+                       break;
+               }
        }
 
-       return ieee80211_sta_commit(sdata);
-}
+       if (!found) {
+               err = -ENOLINK;
+               goto out;
+       }
 
-int ieee80211_sta_set_extra_ie(struct ieee80211_sub_if_data *sdata,
-                              const char *ie, size_t len)
-{
-       struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+       list_del(&found->list);
 
-       if (len == 0 && ifmgd->extra_ie_len == 0)
-               return -EALREADY;
+       wk = krealloc(found, sizeof(*wk) + req->ie_len, GFP_KERNEL);
+       if (!wk) {
+               list_add(&found->list, &ifmgd->work_list);
+               err = -ENOMEM;
+               goto out;
+       }
 
-       if (len == ifmgd->extra_ie_len && ifmgd->extra_ie &&
-           memcmp(ifmgd->extra_ie, ie, len) == 0)
-               return -EALREADY;
+       list_add(&wk->list, &ifmgd->work_list);
 
-       kfree(ifmgd->extra_ie);
-       if (len == 0) {
-               ifmgd->extra_ie = NULL;
-               ifmgd->extra_ie_len = 0;
-               return 0;
-       }
-       ifmgd->extra_ie = kmalloc(len, GFP_KERNEL);
-       if (!ifmgd->extra_ie) {
-               ifmgd->extra_ie_len = 0;
-               return -ENOMEM;
+       ifmgd->flags &= ~IEEE80211_STA_DISABLE_11N;
+
+       for (i = 0; i < req->crypto.n_ciphers_pairwise; i++)
+               if (req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP40 ||
+                   req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_TKIP ||
+                   req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP104)
+                       ifmgd->flags |= IEEE80211_STA_DISABLE_11N;
+
+       sdata->local->oper_channel = req->bss->channel;
+       ieee80211_hw_config(sdata->local, 0);
+
+       if (req->ie && req->ie_len) {
+               memcpy(wk->ie, req->ie, req->ie_len);
+               wk->ie_len = req->ie_len;
+       } else
+               wk->ie_len = 0;
+
+       if (req->prev_bssid)
+               memcpy(wk->prev_bssid, req->prev_bssid, ETH_ALEN);
+
+       wk->state = IEEE80211_MGD_STATE_ASSOC;
+       wk->tries = 0;
+
+       if (req->use_mfp) {
+               ifmgd->mfp = IEEE80211_MFP_REQUIRED;
+               ifmgd->flags |= IEEE80211_STA_MFP_ENABLED;
+       } else {
+               ifmgd->mfp = IEEE80211_MFP_DISABLED;
+               ifmgd->flags &= ~IEEE80211_STA_MFP_ENABLED;
        }
-       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)
-{
-       printk(KERN_DEBUG "%s: deauthenticating by local choice (reason=%d)\n",
-              sdata->dev->name, reason);
+       if (req->crypto.control_port)
+               ifmgd->flags |= IEEE80211_STA_CONTROL_PORT;
+       else
+               ifmgd->flags &= ~IEEE80211_STA_CONTROL_PORT;
 
-       ieee80211_set_disassoc(sdata, true, true, reason);
-       return 0;
+       queue_work(sdata->local->hw.workqueue, &sdata->u.mgd.work);
+
+       err = 0;
+
+ out:
+       mutex_unlock(&ifmgd->mtx);
+       return err;
 }
 
-int ieee80211_sta_disassociate(struct ieee80211_sub_if_data *sdata, u16 reason)
+int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
+                        struct cfg80211_deauth_request *req,
+                        void *cookie)
 {
        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+       struct ieee80211_mgd_work *wk;
+       const u8 *bssid = NULL;
 
-       printk(KERN_DEBUG "%s: disassociating by local choice (reason=%d)\n",
-              sdata->dev->name, reason);
+       printk(KERN_DEBUG "%s: deauthenticating by local choice (reason=%d)\n",
+              sdata->dev->name, req->reason_code);
+
+       mutex_lock(&ifmgd->mtx);
+
+       if (ifmgd->associated && &ifmgd->associated->cbss == req->bss) {
+               bssid = req->bss->bssid;
+               ieee80211_set_disassoc(sdata, bssid, true);
+       } else list_for_each_entry(wk, &ifmgd->work_list, list) {
+               if (&wk->bss->cbss == req->bss) {
+                       bssid = req->bss->bssid;
+                       list_del(&wk->list);
+                       kfree(wk);
+                       break;
+               }
+       }
 
-       if (!(ifmgd->flags & IEEE80211_STA_ASSOCIATED))
+       /* cfg80211 should catch this... */
+       if (WARN_ON(!bssid)) {
+               mutex_unlock(&ifmgd->mtx);
                return -ENOLINK;
+       }
+
+       mutex_unlock(&ifmgd->mtx);
+
+       ieee80211_send_deauth_disassoc(sdata, bssid,
+                       IEEE80211_STYPE_DEAUTH, req->reason_code,
+                       cookie);
 
-       ieee80211_set_disassoc(sdata, false, true, reason);
        return 0;
 }
 
-/* scan finished notification */
-void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local)
+int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata,
+                          struct cfg80211_disassoc_request *req,
+                          void *cookie)
 {
-       struct ieee80211_sub_if_data *sdata = local->scan_sdata;
+       struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
 
-       /* Restart STA timers */
-       rcu_read_lock();
-       list_for_each_entry_rcu(sdata, &local->interfaces, list)
-               ieee80211_restart_sta_timer(sdata);
-       rcu_read_unlock();
-}
+       printk(KERN_DEBUG "%s: disassociating by local choice (reason=%d)\n",
+              sdata->dev->name, req->reason_code);
 
-int ieee80211_max_network_latency(struct notifier_block *nb,
-                                 unsigned long data, void *dummy)
-{
-       s32 latency_usec = (s32) data;
-       struct ieee80211_local *local =
-               container_of(nb, struct ieee80211_local,
-                            network_latency_notifier);
+       mutex_lock(&ifmgd->mtx);
 
-       mutex_lock(&local->iflist_mtx);
-       ieee80211_recalc_ps(local, latency_usec);
-       mutex_unlock(&local->iflist_mtx);
+       /* cfg80211 should catch that */
+       if (WARN_ON(&ifmgd->associated->cbss != req->bss)) {
+               mutex_unlock(&ifmgd->mtx);
+               return -ENOLINK;
+       }
+
+       ieee80211_set_disassoc(sdata, req->bss->bssid, false);
+
+       mutex_unlock(&ifmgd->mtx);
 
+       ieee80211_send_deauth_disassoc(sdata, req->bss->bssid,
+                       IEEE80211_STYPE_DISASSOC, req->reason_code,
+                       cookie);
        return 0;
 }
index de5bba7..fe6b990 100644 (file)
@@ -30,7 +30,6 @@
 static u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
                                           struct tid_ampdu_rx *tid_agg_rx,
                                           struct sk_buff *skb,
-                                          struct ieee80211_rx_status *status,
                                           u16 mpdu_seq_num,
                                           int bar_req);
 /*
@@ -59,11 +58,11 @@ static struct sk_buff *remove_monitor_info(struct ieee80211_local *local,
        return skb;
 }
 
-static inline int should_drop_frame(struct ieee80211_rx_status *status,
-                                   struct sk_buff *skb,
+static inline int should_drop_frame(struct sk_buff *skb,
                                    int present_fcs_len,
                                    int radiotap_len)
 {
+       struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
 
        if (status->flag & (RX_FLAG_FAILED_FCS_CRC | RX_FLAG_FAILED_PLCP_CRC))
@@ -111,10 +110,10 @@ ieee80211_rx_radiotap_len(struct ieee80211_local *local,
 static void
 ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
                                 struct sk_buff *skb,
-                                struct ieee80211_rx_status *status,
                                 struct ieee80211_rate *rate,
                                 int rtap_len)
 {
+       struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
        struct ieee80211_radiotap_header *rthdr;
        unsigned char *pos;
 
@@ -220,9 +219,9 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
  */
 static struct sk_buff *
 ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
-                    struct ieee80211_rx_status *status,
                     struct ieee80211_rate *rate)
 {
+       struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(origskb);
        struct ieee80211_sub_if_data *sdata;
        int needed_headroom = 0;
        struct sk_buff *skb, *skb2;
@@ -248,8 +247,7 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
                present_fcs_len = FCS_LEN;
 
        if (!local->monitors) {
-               if (should_drop_frame(status, origskb, present_fcs_len,
-                                     rtap_len)) {
+               if (should_drop_frame(origskb, present_fcs_len, rtap_len)) {
                        dev_kfree_skb(origskb);
                        return NULL;
                }
@@ -257,7 +255,7 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
                return remove_monitor_info(local, origskb, rtap_len);
        }
 
-       if (should_drop_frame(status, origskb, present_fcs_len, rtap_len)) {
+       if (should_drop_frame(origskb, present_fcs_len, rtap_len)) {
                /* only need to expand headroom if necessary */
                skb = origskb;
                origskb = NULL;
@@ -289,7 +287,7 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
 
        /* if necessary, prepend radiotap information */
        if (!(status->flag & RX_FLAG_RADIOTAP))
-               ieee80211_add_rx_radiotap_header(local, skb, status, rate,
+               ieee80211_add_rx_radiotap_header(local, skb, rate,
                                                 needed_headroom);
 
        skb_reset_mac_header(skb);
@@ -421,12 +419,11 @@ ieee80211_rx_h_passive_scan(struct ieee80211_rx_data *rx)
        struct sk_buff *skb = rx->skb;
 
        if (unlikely(local->hw_scanning))
-               return ieee80211_scan_rx(rx->sdata, skb, rx->status);
+               return ieee80211_scan_rx(rx->sdata, skb);
 
        if (unlikely(local->sw_scanning)) {
                /* drop all the other packets during a software scan anyway */
-               if (ieee80211_scan_rx(rx->sdata, skb, rx->status)
-                   != RX_QUEUED)
+               if (ieee80211_scan_rx(rx->sdata, skb) != RX_QUEUED)
                        dev_kfree_skb(skb);
                return RX_QUEUED;
        }
@@ -1620,7 +1617,7 @@ ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx)
                /* manage reordering buffer according to requested */
                /* sequence number */
                rcu_read_lock();
-               ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, NULL, NULL,
+               ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, NULL,
                                                 start_seq_num, 1);
                rcu_read_unlock();
                return RX_DROP_UNUSABLE;
@@ -1644,12 +1641,7 @@ static void ieee80211_process_sa_query_req(struct ieee80211_sub_if_data *sdata,
 
        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.mgd.state == IEEE80211_STA_MLME_ASSOCIATE) {
-               /* Association in progress; ignore SA Query */
+               /* Not from the current AP or not associated yet. */
                return;
        }
 
@@ -1686,7 +1678,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_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data;
-       struct ieee80211_bss *bss;
        int len = rx->skb->len;
 
        if (!ieee80211_is_action(mgmt->frame_control))
@@ -1764,17 +1755,7 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
                        if (memcmp(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN))
                                return RX_DROP_MONITOR;
 
-                       bss = ieee80211_rx_bss_get(local, sdata->u.mgd.bssid,
-                                          local->hw.conf.channel->center_freq,
-                                          sdata->u.mgd.ssid,
-                                          sdata->u.mgd.ssid_len);
-                       if (!bss)
-                               return RX_DROP_MONITOR;
-
-                       ieee80211_sta_process_chanswitch(sdata,
-                                    &mgmt->u.action.u.chan_switch.sw_elem, bss);
-                       ieee80211_rx_bss_put(local, bss);
-                       break;
+                       return ieee80211_sta_rx_mgmt(sdata, rx->skb);
                }
                break;
        case WLAN_CATEGORY_SA_QUERY:
@@ -1817,13 +1798,13 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx)
                return RX_DROP_MONITOR;
 
        if (ieee80211_vif_is_mesh(&sdata->vif))
-               return ieee80211_mesh_rx_mgmt(sdata, rx->skb, rx->status);
+               return ieee80211_mesh_rx_mgmt(sdata, rx->skb);
 
        if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
-               return ieee80211_ibss_rx_mgmt(sdata, rx->skb, rx->status);
+               return ieee80211_ibss_rx_mgmt(sdata, rx->skb);
 
        if (sdata->vif.type == NL80211_IFTYPE_STATION)
-               return ieee80211_sta_rx_mgmt(sdata, rx->skb, rx->status);
+               return ieee80211_sta_rx_mgmt(sdata, rx->skb);
 
        return RX_DROP_MONITOR;
 }
@@ -1866,7 +1847,8 @@ static void ieee80211_rx_michael_mic_report(struct net_device *dev,
            !ieee80211_is_auth(hdr->frame_control))
                goto ignore;
 
-       mac80211_ev_michael_mic_failure(rx->sdata, keyidx, hdr, NULL);
+       mac80211_ev_michael_mic_failure(rx->sdata, keyidx, hdr, NULL,
+                                       GFP_ATOMIC);
  ignore:
        dev_kfree_skb(rx->skb);
        rx->skb = NULL;
@@ -2028,13 +2010,8 @@ 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.mgd.bssid)) {
-                       if (!(rx->flags & IEEE80211_RX_IN_SCAN))
-                               return 0;
-                       rx->flags &= ~IEEE80211_RX_RA_MATCH;
-               } else if (!multicast &&
-                          compare_ether_addr(sdata->dev->dev_addr,
-                                             hdr->addr1) != 0) {
+               if (!multicast &&
+                   compare_ether_addr(sdata->dev->dev_addr, hdr->addr1) != 0) {
                        if (!(sdata->dev->flags & IFF_PROMISC))
                                return 0;
                        rx->flags &= ~IEEE80211_RX_RA_MATCH;
@@ -2114,9 +2091,9 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
  */
 static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
                                         struct sk_buff *skb,
-                                        struct ieee80211_rx_status *status,
                                         struct ieee80211_rate *rate)
 {
+       struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
        struct ieee80211_local *local = hw_to_local(hw);
        struct ieee80211_sub_if_data *sdata;
        struct ieee80211_hdr *hdr;
@@ -2227,20 +2204,21 @@ static void ieee80211_release_reorder_frame(struct ieee80211_hw *hw,
 {
        struct ieee80211_supported_band *sband;
        struct ieee80211_rate *rate;
-       struct ieee80211_rx_status status;
+       struct sk_buff *skb = tid_agg_rx->reorder_buf[index];
+       struct ieee80211_rx_status *status;
 
-       if (!tid_agg_rx->reorder_buf[index])
+       if (!skb)
                goto no_frame;
 
+       status = IEEE80211_SKB_RXCB(skb);
+
        /* release the reordered frames to stack */
-       memcpy(&status, tid_agg_rx->reorder_buf[index]->cb, sizeof(status));
-       sband = hw->wiphy->bands[status.band];
-       if (status.flag & RX_FLAG_HT)
+       sband = hw->wiphy->bands[status->band];
+       if (status->flag & RX_FLAG_HT)
                rate = sband->bitrates; /* TODO: HT rates */
        else
-               rate = &sband->bitrates[status.rate_idx];
-       __ieee80211_rx_handle_packet(hw, tid_agg_rx->reorder_buf[index],
-                                    &status, rate);
+               rate = &sband->bitrates[status->rate_idx];
+       __ieee80211_rx_handle_packet(hw, skb, rate);
        tid_agg_rx->stored_mpdu_num--;
        tid_agg_rx->reorder_buf[index] = NULL;
 
@@ -2265,7 +2243,6 @@ no_frame:
 static u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
                                           struct tid_ampdu_rx *tid_agg_rx,
                                           struct sk_buff *skb,
-                                          struct ieee80211_rx_status *rxstatus,
                                           u16 mpdu_seq_num,
                                           int bar_req)
 {
@@ -2324,8 +2301,6 @@ static u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
        /* put the frame in the reordering buffer */
        tid_agg_rx->reorder_buf[index] = skb;
        tid_agg_rx->reorder_time[index] = jiffies;
-       memcpy(tid_agg_rx->reorder_buf[index]->cb, rxstatus,
-              sizeof(*rxstatus));
        tid_agg_rx->stored_mpdu_num++;
        /* release the buffer until next missing frame */
        index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn)
@@ -2374,8 +2349,7 @@ static u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
 }
 
 static u8 ieee80211_rx_reorder_ampdu(struct ieee80211_local *local,
-                                    struct sk_buff *skb,
-                                    struct ieee80211_rx_status *status)
+                                    struct sk_buff *skb)
 {
        struct ieee80211_hw *hw = &local->hw;
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
@@ -2424,7 +2398,7 @@ static u8 ieee80211_rx_reorder_ampdu(struct ieee80211_local *local,
 
        /* according to mpdu sequence number deal with reordering buffer */
        mpdu_seq_num = (sc & IEEE80211_SCTL_SEQ) >> 4;
-       ret = ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, skb, status,
+       ret = ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, skb,
                                                mpdu_seq_num, 0);
  end_reorder:
        return ret;
@@ -2434,12 +2408,12 @@ static u8 ieee80211_rx_reorder_ampdu(struct ieee80211_local *local,
  * This is the receive path handler. It is called by a low level driver when an
  * 802.11 MPDU is received from the hardware.
  */
-void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb,
-                   struct ieee80211_rx_status *status)
+void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb)
 {
        struct ieee80211_local *local = hw_to_local(hw);
        struct ieee80211_rate *rate = NULL;
        struct ieee80211_supported_band *sband;
+       struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
 
        if (status->band < 0 ||
            status->band >= IEEE80211_NUM_BANDS) {
@@ -2482,7 +2456,7 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb,
         * if it was previously present.
         * Also, frames with less than 16 bytes are dropped.
         */
-       skb = ieee80211_rx_monitor(local, skb, status, rate);
+       skb = ieee80211_rx_monitor(local, skb, rate);
        if (!skb) {
                rcu_read_unlock();
                return;
@@ -2500,8 +2474,8 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb,
         * frames from other than operational channel), but that should not
         * happen in normal networks.
         */
-       if (!ieee80211_rx_reorder_ampdu(local, skb, status))
-               __ieee80211_rx_handle_packet(hw, skb, status, rate);
+       if (!ieee80211_rx_reorder_ampdu(local, skb))
+               __ieee80211_rx_handle_packet(hw, skb, rate);
 
        rcu_read_unlock();
 }
@@ -2509,16 +2483,13 @@ EXPORT_SYMBOL(__ieee80211_rx);
 
 /* This is a version of the rx handler that can be called from hard irq
  * context. Post the skb on the queue and schedule the tasklet */
-void ieee80211_rx_irqsafe(struct ieee80211_hw *hw, struct sk_buff *skb,
-                         struct ieee80211_rx_status *status)
+void ieee80211_rx_irqsafe(struct ieee80211_hw *hw, struct sk_buff *skb)
 {
        struct ieee80211_local *local = hw_to_local(hw);
 
        BUILD_BUG_ON(sizeof(struct ieee80211_rx_status) > sizeof(skb->cb));
 
        skb->dev = local->mdev;
-       /* copy status into skb->cb for use by tasklet */
-       memcpy(skb->cb, status, sizeof(*status));
        skb->pkt_type = IEEE80211_RX_MSG;
        skb_queue_tail(&local->skb_queue, skb);
        tasklet_schedule(&local->tasklet);
index 2a8d09a..5f4f786 100644 (file)
@@ -26,7 +26,7 @@
 
 #define IEEE80211_PROBE_DELAY (HZ / 33)
 #define IEEE80211_CHANNEL_TIME (HZ / 33)
-#define IEEE80211_PASSIVE_CHANNEL_TIME (HZ / 5)
+#define IEEE80211_PASSIVE_CHANNEL_TIME (HZ / 8)
 
 struct ieee80211_bss *
 ieee80211_rx_bss_get(struct ieee80211_local *local, u8 *bssid, int freq,
@@ -121,23 +121,10 @@ ieee80211_bss_info_update(struct ieee80211_local *local,
        return bss;
 }
 
-void ieee80211_rx_bss_remove(struct ieee80211_sub_if_data *sdata, u8 *bssid,
-                            int freq, u8 *ssid, u8 ssid_len)
-{
-       struct ieee80211_bss *bss;
-       struct ieee80211_local *local = sdata->local;
-
-       bss = ieee80211_rx_bss_get(local, bssid, freq, ssid, ssid_len);
-       if (bss) {
-               cfg80211_unlink_bss(local->hw.wiphy, (void *)bss);
-               ieee80211_rx_bss_put(local, bss);
-       }
-}
-
 ieee80211_rx_result
-ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb,
-                 struct ieee80211_rx_status *rx_status)
+ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
 {
+       struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb);
        struct ieee80211_mgmt *mgmt;
        struct ieee80211_bss *bss;
        u8 *elements;
@@ -327,7 +314,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.mgd.flags & IEEE80211_STA_ASSOCIATED) {
+                       if (sdata->u.mgd.associated) {
                                ieee80211_scan_ps_disable(sdata);
                                netif_tx_wake_all_queues(sdata->dev);
                        }
@@ -383,7 +370,7 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local)
                                sdata, BSS_CHANGED_BEACON_ENABLED);
 
                if (sdata->vif.type == NL80211_IFTYPE_STATION) {
-                       if (sdata->u.mgd.flags & IEEE80211_STA_ASSOCIATED) {
+                       if (sdata->u.mgd.associated) {
                                netif_tx_stop_all_queues(sdata->dev);
                                ieee80211_scan_ps_enable(sdata);
                        }
@@ -443,10 +430,8 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
 
        if (req != &local->int_scan_req &&
            sdata->vif.type == NL80211_IFTYPE_STATION &&
-           (ifmgd->state == IEEE80211_STA_MLME_DIRECT_PROBE ||
-            ifmgd->state == IEEE80211_STA_MLME_AUTHENTICATE ||
-            ifmgd->state == IEEE80211_STA_MLME_ASSOCIATE)) {
-               /* actually wait for the assoc to finish/time out */
+           !list_empty(&ifmgd->work_list)) {
+               /* actually wait for the work it's doing to finish/time out */
                set_bit(IEEE80211_STA_REQ_SCAN, &ifmgd->request);
                return 0;
        }
index 49a1a1f..4ecf10a 100644 (file)
@@ -308,6 +308,23 @@ struct sta_info {
                struct dentry *inactive_ms;
                struct dentry *last_seq_ctrl;
                struct dentry *agg_status;
+               struct dentry *aid;
+               struct dentry *dev;
+               struct dentry *rx_packets;
+               struct dentry *tx_packets;
+               struct dentry *rx_bytes;
+               struct dentry *tx_bytes;
+               struct dentry *rx_duplicates;
+               struct dentry *rx_fragments;
+               struct dentry *rx_dropped;
+               struct dentry *tx_fragments;
+               struct dentry *tx_filtered;
+               struct dentry *tx_retry_failed;
+               struct dentry *tx_retry_count;
+               struct dentry *last_signal;
+               struct dentry *last_qual;
+               struct dentry *last_noise;
+               struct dentry *wep_weak_iv_count;
                bool add_has_run;
        } debugfs;
 #endif
index 3a8922c..60ae086 100644 (file)
@@ -1627,7 +1627,7 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
        u32 sta_flags = 0;
 
        if (unlikely(skb->len < ETH_HLEN)) {
-               ret = 0;
+               ret = NETDEV_TX_OK;
                goto fail;
        }
 
@@ -1664,7 +1664,7 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
                if (!sdata->u.mesh.mshcfg.dot11MeshTTL) {
                        /* Do not send frames with mesh_ttl == 0 */
                        sdata->u.mesh.mshstats.dropped_frames_ttl++;
-                       ret = 0;
+                       ret = NETDEV_TX_OK;
                        goto fail;
                }
                memset(&mesh_hdr, 0, sizeof(mesh_hdr));
@@ -1724,7 +1724,7 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
                hdrlen = 24;
                break;
        default:
-               ret = 0;
+               ret = NETDEV_TX_OK;
                goto fail;
        }
 
@@ -1766,7 +1766,7 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
 
                I802_DEBUG_INC(local->tx_handlers_drop_unauth_port);
 
-               ret = 0;
+               ret = NETDEV_TX_OK;
                goto fail;
        }
 
@@ -1858,10 +1858,10 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
        dev->trans_start = jiffies;
        dev_queue_xmit(skb);
 
-       return 0;
+       return NETDEV_TX_OK;
 
  fail:
-       if (!ret)
+       if (ret == NETDEV_TX_OK)
                dev_kfree_skb(skb);
 
        return ret;
index ef73105..4fafb2d 100644 (file)
@@ -67,10 +67,10 @@ static inline bool ieee80211_wep_weak_iv(u32 iv, int keylen)
 
 
 static void ieee80211_wep_get_iv(struct ieee80211_local *local,
-                                struct ieee80211_key *key, u8 *iv)
+                                int keylen, int keyidx, u8 *iv)
 {
        local->wep_iv++;
-       if (ieee80211_wep_weak_iv(local->wep_iv, key->conf.keylen))
+       if (ieee80211_wep_weak_iv(local->wep_iv, keylen))
                local->wep_iv += 0x0100;
 
        if (!iv)
@@ -79,13 +79,13 @@ static void ieee80211_wep_get_iv(struct ieee80211_local *local,
        *iv++ = (local->wep_iv >> 16) & 0xff;
        *iv++ = (local->wep_iv >> 8) & 0xff;
        *iv++ = local->wep_iv & 0xff;
-       *iv++ = key->conf.keyidx << 6;
+       *iv++ = keyidx << 6;
 }
 
 
 static u8 *ieee80211_wep_add_iv(struct ieee80211_local *local,
                                struct sk_buff *skb,
-                               struct ieee80211_key *key)
+                               int keylen, int keyidx)
 {
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
        unsigned int hdrlen;
@@ -100,7 +100,7 @@ static u8 *ieee80211_wep_add_iv(struct ieee80211_local *local,
        hdrlen = ieee80211_hdrlen(hdr->frame_control);
        newhdr = skb_push(skb, WEP_IV_LEN);
        memmove(newhdr, newhdr + WEP_IV_LEN, hdrlen);
-       ieee80211_wep_get_iv(local, key, newhdr + hdrlen);
+       ieee80211_wep_get_iv(local, keylen, keyidx, newhdr + hdrlen);
        return newhdr + hdrlen;
 }
 
@@ -144,26 +144,17 @@ void ieee80211_wep_encrypt_data(struct crypto_blkcipher *tfm, u8 *rc4key,
  *
  * WEP frame payload: IV + TX key idx, RC4(data), ICV = RC4(CRC32(data))
  */
-int ieee80211_wep_encrypt(struct ieee80211_local *local, struct sk_buff *skb,
-                         struct ieee80211_key *key)
+static int ieee80211_wep_encrypt(struct ieee80211_local *local,
+                                struct sk_buff *skb,
+                                const u8 *key, int keylen, int keyidx)
 {
-       u32 klen;
-       u8 *rc4key, *iv;
+       u8 *iv;
        size_t len;
+       u8 rc4key[3 + WLAN_KEY_LEN_WEP104];
 
-       if (!key || key->conf.alg != ALG_WEP)
-               return -1;
-
-       klen = 3 + key->conf.keylen;
-       rc4key = kmalloc(klen, GFP_ATOMIC);
-       if (!rc4key)
-               return -1;
-
-       iv = ieee80211_wep_add_iv(local, skb, key);
-       if (!iv) {
-               kfree(rc4key);
+       iv = ieee80211_wep_add_iv(local, skb, keylen, keyidx);
+       if (!iv)
                return -1;
-       }
 
        len = skb->len - (iv + WEP_IV_LEN - skb->data);
 
@@ -171,16 +162,14 @@ int ieee80211_wep_encrypt(struct ieee80211_local *local, struct sk_buff *skb,
        memcpy(rc4key, iv, 3);
 
        /* Copy rest of the WEP key (the secret part) */
-       memcpy(rc4key + 3, key->conf.key, key->conf.keylen);
+       memcpy(rc4key + 3, keykeylen);
 
        /* Add room for ICV */
        skb_put(skb, WEP_ICV_LEN);
 
-       ieee80211_wep_encrypt_data(local->wep_tx_tfm, rc4key, klen,
+       ieee80211_wep_encrypt_data(local->wep_tx_tfm, rc4key, keylen + 3,
                                   iv + WEP_IV_LEN, len);
 
-       kfree(rc4key);
-
        return 0;
 }
 
@@ -216,8 +205,9 @@ int ieee80211_wep_decrypt_data(struct crypto_blkcipher *tfm, u8 *rc4key,
  * failure. If frame is OK, IV and ICV will be removed, i.e., decrypted payload
  * is moved to the beginning of the skb and skb length will be reduced.
  */
-int ieee80211_wep_decrypt(struct ieee80211_local *local, struct sk_buff *skb,
-                         struct ieee80211_key *key)
+static int ieee80211_wep_decrypt(struct ieee80211_local *local,
+                                struct sk_buff *skb,
+                                struct ieee80211_key *key)
 {
        u32 klen;
        u8 *rc4key;
@@ -314,12 +304,16 @@ static int wep_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb)
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 
        if (!(tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) {
-               if (ieee80211_wep_encrypt(tx->local, skb, tx->key))
+               if (ieee80211_wep_encrypt(tx->local, skb, tx->key->conf.key,
+                                         tx->key->conf.keylen,
+                                         tx->key->conf.keyidx))
                        return -1;
        } else {
                info->control.hw_key = &tx->key->conf;
                if (tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV) {
-                       if (!ieee80211_wep_add_iv(tx->local, skb, tx->key))
+                       if (!ieee80211_wep_add_iv(tx->local, skb,
+                                                 tx->key->conf.keylen,
+                                                 tx->key->conf.keyidx))
                                return -1;
                }
        }
index d3f0db4..85219de 100644 (file)
@@ -22,10 +22,6 @@ void ieee80211_wep_encrypt_data(struct crypto_blkcipher *tfm, u8 *rc4key,
                                size_t klen, u8 *data, size_t data_len);
 int ieee80211_wep_decrypt_data(struct crypto_blkcipher *tfm, u8 *rc4key,
                               size_t klen, u8 *data, size_t data_len);
-int ieee80211_wep_encrypt(struct ieee80211_local *local, struct sk_buff *skb,
-                         struct ieee80211_key *key);
-int ieee80211_wep_decrypt(struct ieee80211_local *local, struct sk_buff *skb,
-                         struct ieee80211_key *key);
 bool ieee80211_wep_is_weak_iv(struct sk_buff *skb, struct ieee80211_key *key);
 
 ieee80211_rx_result
index 1da81f4..5acb814 100644 (file)
 #include "aes_ccm.h"
 
 
-static int ieee80211_ioctl_siwgenie(struct net_device *dev,
-                                   struct iw_request_info *info,
-                                   struct iw_point *data, char *extra)
-{
-       struct ieee80211_sub_if_data *sdata;
-
-       sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-
-       if (sdata->vif.type == NL80211_IFTYPE_STATION) {
-               int ret = ieee80211_sta_set_extra_ie(sdata, extra, data->length);
-               if (ret && ret != -EALREADY)
-                       return ret;
-               sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_BSSID_SEL;
-               sdata->u.mgd.flags &= ~IEEE80211_STA_EXT_SME;
-               sdata->u.mgd.flags &= ~IEEE80211_STA_CONTROL_PORT;
-               if (ret != -EALREADY)
-                       ieee80211_sta_req_auth(sdata);
-               return 0;
-       }
-
-       return -EOPNOTSUPP;
-}
-
 static int ieee80211_ioctl_siwfreq(struct net_device *dev,
                                   struct iw_request_info *info,
                                   struct iw_freq *freq, char *extra)
@@ -61,16 +38,13 @@ static int ieee80211_ioctl_siwfreq(struct net_device *dev,
        if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
                return cfg80211_ibss_wext_siwfreq(dev, info, freq, extra);
        else if (sdata->vif.type == NL80211_IFTYPE_STATION)
-               sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_CHANNEL_SEL;
+               return cfg80211_mgd_wext_siwfreq(dev, info, freq, extra);
 
        /* 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_STATION)
-                               sdata->u.mgd.flags |=
-                                       IEEE80211_STA_AUTO_CHANNEL_SEL;
-                       return 0;
-               } else
+               if (freq->m < 0)
+                       return -EINVAL;
+               else
                        chan = ieee80211_get_channel(local->hw.wiphy,
                                ieee80211_channel_to_frequency(freq->m));
        } else {
@@ -95,9 +69,6 @@ static int ieee80211_ioctl_siwfreq(struct net_device *dev,
        if (local->oper_channel == chan)
                return 0;
 
-       if (sdata->vif.type == NL80211_IFTYPE_STATION)
-               ieee80211_sta_req_auth(sdata);
-
        local->oper_channel = chan;
        local->oper_channel_type = NL80211_CHAN_NO_HT;
        ieee80211_hw_config(local, 0);
@@ -115,6 +86,8 @@ static int ieee80211_ioctl_giwfreq(struct net_device *dev,
 
        if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
                return cfg80211_ibss_wext_giwfreq(dev, info, freq, extra);
+       else if (sdata->vif.type == NL80211_IFTYPE_STATION)
+               return cfg80211_mgd_wext_giwfreq(dev, info, freq, extra);
 
        freq->m = local->oper_channel->center_freq;
        freq->e = 6;
@@ -128,31 +101,11 @@ static int ieee80211_ioctl_siwessid(struct net_device *dev,
                                    struct iw_point *data, char *ssid)
 {
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-       size_t len = data->length;
-       int ret;
 
        if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
                return cfg80211_ibss_wext_siwessid(dev, info, data, ssid);
-
-       /* iwconfig uses nul termination in SSID.. */
-       if (len > 0 && ssid[len - 1] == '\0')
-               len--;
-
-       if (sdata->vif.type == NL80211_IFTYPE_STATION) {
-               if (data->flags)
-                       sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_SSID_SEL;
-               else
-                       sdata->u.mgd.flags |= IEEE80211_STA_AUTO_SSID_SEL;
-
-               ret = ieee80211_sta_set_ssid(sdata, ssid, len);
-               if (ret)
-                       return ret;
-
-               sdata->u.mgd.flags &= ~IEEE80211_STA_EXT_SME;
-               sdata->u.mgd.flags &= ~IEEE80211_STA_CONTROL_PORT;
-               ieee80211_sta_req_auth(sdata);
-               return 0;
-       }
+       else if (sdata->vif.type == NL80211_IFTYPE_STATION)
+               return cfg80211_mgd_wext_siwessid(dev, info, data, ssid);
 
        return -EOPNOTSUPP;
 }
@@ -162,23 +115,14 @@ static int ieee80211_ioctl_giwessid(struct net_device *dev,
                                    struct iw_request_info *info,
                                    struct iw_point *data, char *ssid)
 {
-       size_t len;
        struct ieee80211_sub_if_data *sdata;
 
        sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
        if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
                return cfg80211_ibss_wext_giwessid(dev, info, data, ssid);
-
-       if (sdata->vif.type == NL80211_IFTYPE_STATION) {
-               int res = ieee80211_sta_get_ssid(sdata, ssid, &len);
-               if (res == 0) {
-                       data->length = len;
-                       data->flags = 1;
-               } else
-                       data->flags = 0;
-               return res;
-       }
+       else if (sdata->vif.type == NL80211_IFTYPE_STATION)
+               return cfg80211_mgd_wext_giwessid(dev, info, data, ssid);
 
        return -EOPNOTSUPP;
 }
@@ -193,40 +137,11 @@ static int ieee80211_ioctl_siwap(struct net_device *dev,
        if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
                return cfg80211_ibss_wext_siwap(dev, info, ap_addr, extra);
 
-       if (sdata->vif.type == NL80211_IFTYPE_STATION) {
-               int ret;
-
-               if (is_zero_ether_addr((u8 *) &ap_addr->sa_data))
-                       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.mgd.flags |= IEEE80211_STA_AUTO_BSSID_SEL;
-               else
-                       sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_BSSID_SEL;
-               ret = ieee80211_sta_set_bssid(sdata, (u8 *) &ap_addr->sa_data);
-               if (ret)
-                       return ret;
-               sdata->u.mgd.flags &= ~IEEE80211_STA_EXT_SME;
-               sdata->u.mgd.flags &= ~IEEE80211_STA_CONTROL_PORT;
-               ieee80211_sta_req_auth(sdata);
-               return 0;
-       } else if (sdata->vif.type == NL80211_IFTYPE_WDS) {
-               /*
-                * If it is necessary to update the WDS peer address
-                * while the interface is running, then we need to do
-                * more work here, namely if it is running we need to
-                * add a new and remove the old STA entry, this is
-                * normally handled by _open() and _stop().
-                */
-               if (netif_running(dev))
-                       return -EBUSY;
-
-               memcpy(&sdata->u.wds.remote_addr, (u8 *) &ap_addr->sa_data,
-                      ETH_ALEN);
-
-               return 0;
-       }
+       if (sdata->vif.type == NL80211_IFTYPE_STATION)
+               return cfg80211_mgd_wext_siwap(dev, info, ap_addr, extra);
 
+       if (sdata->vif.type == NL80211_IFTYPE_WDS)
+               return cfg80211_wds_wext_siwap(dev, info, ap_addr, extra);
        return -EOPNOTSUPP;
 }
 
@@ -240,326 +155,13 @@ static int ieee80211_ioctl_giwap(struct net_device *dev,
        if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
                return cfg80211_ibss_wext_giwap(dev, info, ap_addr, extra);
 
-       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.mgd.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);
-               return 0;
-       }
-
-       return -EOPNOTSUPP;
-}
-
-
-static int ieee80211_ioctl_siwrate(struct net_device *dev,
-                                 struct iw_request_info *info,
-                                 struct iw_param *rate, char *extra)
-{
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-       int i, err = -EINVAL;
-       u32 target_rate = rate->value / 100000;
-       struct ieee80211_sub_if_data *sdata;
-       struct ieee80211_supported_band *sband;
-
-       sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-
-       sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
-
-       /* target_rate = -1, rate->fixed = 0 means auto only, so use all rates
-        * target_rate = X, rate->fixed = 1 means only rate X
-        * target_rate = X, rate->fixed = 0 means all rates <= X */
-       sdata->max_ratectrl_rateidx = -1;
-       sdata->force_unicast_rateidx = -1;
-       if (rate->value < 0)
-               return 0;
-
-       for (i=0; i< sband->n_bitrates; i++) {
-               struct ieee80211_rate *brate = &sband->bitrates[i];
-               int this_rate = brate->bitrate;
-
-               if (target_rate == this_rate) {
-                       sdata->max_ratectrl_rateidx = i;
-                       if (rate->fixed)
-                               sdata->force_unicast_rateidx = i;
-                       err = 0;
-                       break;
-               }
-       }
-       return err;
-}
-
-static int ieee80211_ioctl_giwrate(struct net_device *dev,
-                                 struct iw_request_info *info,
-                                 struct iw_param *rate, char *extra)
-{
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-       struct sta_info *sta;
-       struct ieee80211_sub_if_data *sdata;
-       struct ieee80211_supported_band *sband;
-
-       sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-
-       if (sdata->vif.type != NL80211_IFTYPE_STATION)
-               return -EOPNOTSUPP;
-
-       sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
-
-       rcu_read_lock();
-
-       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;
-       else
-               rate->value = 0;
-
-       rcu_read_unlock();
-
-       if (!sta)
-               return -ENODEV;
-
-       rate->value *= 100000;
-
-       return 0;
-}
-
-static int ieee80211_ioctl_siwpower(struct net_device *dev,
-                                   struct iw_request_info *info,
-                                   struct iw_param *wrq,
-                                   char *extra)
-{
-       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-       struct ieee80211_conf *conf = &local->hw.conf;
-       int timeout = 0;
-       bool ps;
-
-       if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_PS))
-               return -EOPNOTSUPP;
-
-       if (sdata->vif.type != NL80211_IFTYPE_STATION)
-               return -EINVAL;
-
-       if (wrq->disabled) {
-               ps = false;
-               timeout = 0;
-               goto set;
-       }
-
-       switch (wrq->flags & IW_POWER_MODE) {
-       case IW_POWER_ON:       /* If not specified */
-       case IW_POWER_MODE:     /* If set all mask */
-       case IW_POWER_ALL_R:    /* If explicitely state all */
-               ps = true;
-               break;
-       default:                /* Otherwise we ignore */
-               return -EINVAL;
-       }
-
-       if (wrq->flags & ~(IW_POWER_MODE | IW_POWER_TIMEOUT))
-               return -EINVAL;
-
-       if (wrq->flags & IW_POWER_TIMEOUT)
-               timeout = wrq->value / 1000;
-
- set:
-       if (ps == sdata->u.mgd.powersave && timeout == conf->dynamic_ps_timeout)
-               return 0;
-
-       sdata->u.mgd.powersave = ps;
-       conf->dynamic_ps_timeout = timeout;
-
-       if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS)
-               ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
-
-       ieee80211_recalc_ps(local, -1);
-
-       return 0;
-}
-
-static int ieee80211_ioctl_giwpower(struct net_device *dev,
-                                   struct iw_request_info *info,
-                                   union iwreq_data *wrqu,
-                                   char *extra)
-{
-       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-
-       wrqu->power.disabled = !sdata->u.mgd.powersave;
-
-       return 0;
-}
-
-static int ieee80211_ioctl_siwauth(struct net_device *dev,
-                                  struct iw_request_info *info,
-                                  struct iw_param *data, char *extra)
-{
-       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-       int ret = 0;
-
-       switch (data->flags & IW_AUTH_INDEX) {
-       case IW_AUTH_WPA_VERSION:
-       case IW_AUTH_CIPHER_GROUP:
-       case IW_AUTH_WPA_ENABLED:
-       case IW_AUTH_RX_UNENCRYPTED_EAPOL:
-       case IW_AUTH_KEY_MGMT:
-       case IW_AUTH_CIPHER_GROUP_MGMT:
-               break;
-       case IW_AUTH_CIPHER_PAIRWISE:
-               if (sdata->vif.type == NL80211_IFTYPE_STATION) {
-                       if (data->value & (IW_AUTH_CIPHER_WEP40 |
-                           IW_AUTH_CIPHER_WEP104 | IW_AUTH_CIPHER_TKIP))
-                               sdata->u.mgd.flags |=
-                                       IEEE80211_STA_TKIP_WEP_USED;
-                       else
-                               sdata->u.mgd.flags &=
-                                       ~IEEE80211_STA_TKIP_WEP_USED;
-               }
-               break;
-       case IW_AUTH_DROP_UNENCRYPTED:
-               sdata->drop_unencrypted = !!data->value;
-               break;
-       case IW_AUTH_PRIVACY_INVOKED:
-               if (sdata->vif.type != NL80211_IFTYPE_STATION)
-                       ret = -EINVAL;
-               else {
-                       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.mgd.flags |=
-                                       IEEE80211_STA_PRIVACY_INVOKED;
-               }
-               break;
-       case IW_AUTH_80211_AUTH_ALG:
-               if (sdata->vif.type == NL80211_IFTYPE_STATION)
-                       sdata->u.mgd.auth_algs = data->value;
-               else
-                       ret = -EOPNOTSUPP;
-               break;
-       case IW_AUTH_MFP:
-               if (!(sdata->local->hw.flags & IEEE80211_HW_MFP_CAPABLE)) {
-                       ret = -EOPNOTSUPP;
-                       break;
-               }
-               if (sdata->vif.type == NL80211_IFTYPE_STATION) {
-                       switch (data->value) {
-                       case IW_AUTH_MFP_DISABLED:
-                               sdata->u.mgd.mfp = IEEE80211_MFP_DISABLED;
-                               break;
-                       case IW_AUTH_MFP_OPTIONAL:
-                               sdata->u.mgd.mfp = IEEE80211_MFP_OPTIONAL;
-                               break;
-                       case IW_AUTH_MFP_REQUIRED:
-                               sdata->u.mgd.mfp = IEEE80211_MFP_REQUIRED;
-                               break;
-                       default:
-                               ret = -EINVAL;
-                       }
-               } else
-                       ret = -EOPNOTSUPP;
-               break;
-       default:
-               ret = -EOPNOTSUPP;
-               break;
-       }
-       return ret;
-}
-
-/* Get wireless statistics.  Called by /proc/net/wireless and by SIOCGIWSTATS */
-static struct iw_statistics *ieee80211_get_wireless_stats(struct net_device *dev)
-{
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-       struct iw_statistics *wstats = &local->wstats;
-       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-       struct sta_info *sta = NULL;
-
-       rcu_read_lock();
-
        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;
-               wstats->qual.qual = 0;
-               wstats->qual.level = 0;
-               wstats->qual.noise = 0;
-               wstats->qual.updated = IW_QUAL_ALL_INVALID;
-       } else {
-               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;
-               }
-       }
+               return cfg80211_mgd_wext_giwap(dev, info, ap_addr, extra);
 
-       rcu_read_unlock();
-
-       return wstats;
-}
+       if (sdata->vif.type == NL80211_IFTYPE_WDS)
+               return cfg80211_wds_wext_giwap(dev, info, ap_addr, extra);
 
-static int ieee80211_ioctl_giwauth(struct net_device *dev,
-                                  struct iw_request_info *info,
-                                  struct iw_param *data, char *extra)
-{
-       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-       int ret = 0;
-
-       switch (data->flags & IW_AUTH_INDEX) {
-       case IW_AUTH_80211_AUTH_ALG:
-               if (sdata->vif.type == NL80211_IFTYPE_STATION)
-                       data->value = sdata->u.mgd.auth_algs;
-               else
-                       ret = -EOPNOTSUPP;
-               break;
-       default:
-               ret = -EOPNOTSUPP;
-               break;
-       }
-       return ret;
+       return -EOPNOTSUPP;
 }
 
 
@@ -599,8 +201,8 @@ static const iw_handler ieee80211_handler[] =
        (iw_handler) NULL,                              /* SIOCGIWNICKN */
        (iw_handler) NULL,                              /* -- hole -- */
        (iw_handler) NULL,                              /* -- hole -- */
-       (iw_handler) ieee80211_ioctl_siwrate,           /* SIOCSIWRATE */
-       (iw_handler) ieee80211_ioctl_giwrate,           /* SIOCGIWRATE */
+       (iw_handler) cfg80211_wext_siwrate,             /* SIOCSIWRATE */
+       (iw_handler) cfg80211_wext_giwrate,             /* SIOCGIWRATE */
        (iw_handler) cfg80211_wext_siwrts,              /* SIOCSIWRTS */
        (iw_handler) cfg80211_wext_giwrts,              /* SIOCGIWRTS */
        (iw_handler) cfg80211_wext_siwfrag,             /* SIOCSIWFRAG */
@@ -611,14 +213,14 @@ static const iw_handler ieee80211_handler[] =
        (iw_handler) cfg80211_wext_giwretry,            /* SIOCGIWRETRY */
        (iw_handler) cfg80211_wext_siwencode,           /* SIOCSIWENCODE */
        (iw_handler) cfg80211_wext_giwencode,           /* SIOCGIWENCODE */
-       (iw_handler) ieee80211_ioctl_siwpower,          /* SIOCSIWPOWER */
-       (iw_handler) ieee80211_ioctl_giwpower,          /* SIOCGIWPOWER */
+       (iw_handler) cfg80211_wext_siwpower,            /* SIOCSIWPOWER */
+       (iw_handler) cfg80211_wext_giwpower,            /* SIOCGIWPOWER */
        (iw_handler) NULL,                              /* -- hole -- */
        (iw_handler) NULL,                              /* -- hole -- */
-       (iw_handler) ieee80211_ioctl_siwgenie,          /* SIOCSIWGENIE */
+       (iw_handler) cfg80211_wext_siwgenie,            /* SIOCSIWGENIE */
        (iw_handler) NULL,                              /* SIOCGIWGENIE */
-       (iw_handler) ieee80211_ioctl_siwauth,           /* SIOCSIWAUTH */
-       (iw_handler) ieee80211_ioctl_giwauth,           /* SIOCGIWAUTH */
+       (iw_handler) cfg80211_wext_siwauth,             /* SIOCSIWAUTH */
+       (iw_handler) cfg80211_wext_giwauth,             /* SIOCGIWAUTH */
        (iw_handler) cfg80211_wext_siwencodeext,        /* SIOCSIWENCODEEXT */
        (iw_handler) NULL,                              /* SIOCGIWENCODEEXT */
        (iw_handler) NULL,                              /* SIOCSIWPMKSA */
@@ -629,5 +231,5 @@ const struct iw_handler_def ieee80211_iw_handler_def =
 {
        .num_standard   = ARRAY_SIZE(ieee80211_handler),
        .standard       = (iw_handler *) ieee80211_handler,
-       .get_wireless_stats = ieee80211_get_wireless_stats,
+       .get_wireless_stats = cfg80211_wireless_stats,
 };
index dcfae88..7077869 100644 (file)
@@ -122,7 +122,8 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_rx_data *rx)
                        return RX_DROP_UNUSABLE;
 
                mac80211_ev_michael_mic_failure(rx->sdata, rx->key->conf.keyidx,
-                                               (void *) skb->data, NULL);
+                                               (void *) skb->data, NULL,
+                                               GFP_ATOMIC);
                return RX_DROP_UNUSABLE;
        }
 
index 7c1333c..2d24d81 100644 (file)
@@ -3231,7 +3231,7 @@ static int ip_vs_genl_get_cmd(struct sk_buff *skb, struct genl_info *info)
        }
 
        genlmsg_end(msg, reply);
-       ret = genlmsg_unicast(msg, info->snd_pid);
+       ret = genlmsg_reply(msg, info);
        goto out;
 
 nla_put_failure:
index 2936fa3..da3163d 100644 (file)
@@ -83,6 +83,11 @@ struct netlink_sock {
        struct module           *module;
 };
 
+struct listeners_rcu_head {
+       struct rcu_head rcu_head;
+       void *ptr;
+};
+
 #define NETLINK_KERNEL_SOCKET  0x1
 #define NETLINK_RECV_PKTINFO   0x2
 #define NETLINK_BROADCAST_SEND_ERROR   0x4
@@ -1356,7 +1361,7 @@ static int netlink_recvmsg(struct kiocb *kiocb, struct socket *sock,
        struct netlink_sock *nlk = nlk_sk(sk);
        int noblock = flags&MSG_DONTWAIT;
        size_t copied;
-       struct sk_buff *skb;
+       struct sk_buff *skb, *frag __maybe_unused = NULL;
        int err;
 
        if (flags&MSG_OOB)
@@ -1368,6 +1373,35 @@ static int netlink_recvmsg(struct kiocb *kiocb, struct socket *sock,
        if (skb == NULL)
                goto out;
 
+#ifdef CONFIG_COMPAT_NETLINK_MESSAGES
+       if (unlikely(skb_shinfo(skb)->frag_list)) {
+               bool need_compat = !!(flags & MSG_CMSG_COMPAT);
+
+               /*
+                * If this skb has a frag_list, then here that means that
+                * we will have to use the frag_list skb for compat tasks
+                * and the regular skb for non-compat tasks.
+                *
+                * The skb might (and likely will) be cloned, so we can't
+                * just reset frag_list and go on with things -- we need to
+                * keep that. For the compat case that's easy -- simply get
+                * a reference to the compat skb and free the regular one
+                * including the frag. For the non-compat case, we need to
+                * avoid sending the frag to the user -- so assign NULL but
+                * restore it below before freeing the skb.
+                */
+               if (need_compat) {
+                       struct sk_buff *compskb = skb_shinfo(skb)->frag_list;
+                       skb_get(compskb);
+                       kfree_skb(skb);
+                       skb = compskb;
+               } else {
+                       frag = skb_shinfo(skb)->frag_list;
+                       skb_shinfo(skb)->frag_list = NULL;
+               }
+       }
+#endif
+
        msg->msg_namelen = 0;
 
        copied = skb->len;
@@ -1398,6 +1432,11 @@ static int netlink_recvmsg(struct kiocb *kiocb, struct socket *sock,
        siocb->scm->creds = *NETLINK_CREDS(skb);
        if (flags & MSG_TRUNC)
                copied = skb->len;
+
+#ifdef CONFIG_COMPAT_NETLINK_MESSAGES
+       skb_shinfo(skb)->frag_list = frag;
+#endif
+
        skb_free_datagram(sk, skb);
 
        if (nlk->cb && atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf / 2)
@@ -1453,7 +1492,8 @@ netlink_kernel_create(struct net *net, int unit, unsigned int groups,
        if (groups < 32)
                groups = 32;
 
-       listeners = kzalloc(NLGRPSZ(groups), GFP_KERNEL);
+       listeners = kzalloc(NLGRPSZ(groups) + sizeof(struct listeners_rcu_head),
+                           GFP_KERNEL);
        if (!listeners)
                goto out_sock_release;
 
@@ -1501,6 +1541,14 @@ netlink_kernel_release(struct sock *sk)
 EXPORT_SYMBOL(netlink_kernel_release);
 
 
+static void netlink_free_old_listeners(struct rcu_head *rcu_head)
+{
+       struct listeners_rcu_head *lrh;
+
+       lrh = container_of(rcu_head, struct listeners_rcu_head, rcu_head);
+       kfree(lrh->ptr);
+}
+
 /**
  * netlink_change_ngroups - change number of multicast groups
  *
@@ -1516,6 +1564,7 @@ EXPORT_SYMBOL(netlink_kernel_release);
 int netlink_change_ngroups(struct sock *sk, unsigned int groups)
 {
        unsigned long *listeners, *old = NULL;
+       struct listeners_rcu_head *old_rcu_head;
        struct netlink_table *tbl = &nl_table[sk->sk_protocol];
        int err = 0;
 
@@ -1524,7 +1573,9 @@ int netlink_change_ngroups(struct sock *sk, unsigned int groups)
 
        netlink_table_grab();
        if (NLGRPSZ(tbl->groups) < NLGRPSZ(groups)) {
-               listeners = kzalloc(NLGRPSZ(groups), GFP_ATOMIC);
+               listeners = kzalloc(NLGRPSZ(groups) +
+                                   sizeof(struct listeners_rcu_head),
+                                   GFP_ATOMIC);
                if (!listeners) {
                        err = -ENOMEM;
                        goto out_ungrab;
@@ -1532,16 +1583,24 @@ int netlink_change_ngroups(struct sock *sk, unsigned int groups)
                old = tbl->listeners;
                memcpy(listeners, old, NLGRPSZ(tbl->groups));
                rcu_assign_pointer(tbl->listeners, listeners);
+               /*
+                * Free the old memory after an RCU grace period so we
+                * don't leak it. We use call_rcu() here in order to be
+                * able to call this function from atomic contexts. The
+                * allocation of this memory will have reserved enough
+                * space for struct listeners_rcu_head at the end.
+                */
+               old_rcu_head = (void *)(tbl->listeners +
+                                       NLGRPLONGS(tbl->groups));
+               old_rcu_head->ptr = old;
+               call_rcu(&old_rcu_head->rcu_head, netlink_free_old_listeners);
        }
        tbl->groups = groups;
 
  out_ungrab:
        netlink_table_ungrab();
-       synchronize_rcu();
-       kfree(old);
        return err;
 }
-EXPORT_SYMBOL(netlink_change_ngroups);
 
 /**
  * netlink_clear_multicast_users - kick off multicast listeners
@@ -1564,7 +1623,6 @@ void netlink_clear_multicast_users(struct sock *ksk, unsigned int group)
 
        netlink_table_ungrab();
 }
-EXPORT_SYMBOL(netlink_clear_multicast_users);
 
 void netlink_set_nonroot(int protocol, unsigned int flags)
 {
index eed4c6a..575c643 100644 (file)
@@ -18,8 +18,6 @@
 #include <net/sock.h>
 #include <net/genetlink.h>
 
-struct sock *genl_sock = NULL;
-
 static DEFINE_MUTEX(genl_mutex); /* serialization of message processing */
 
 static inline void genl_lock(void)
@@ -175,10 +173,31 @@ int genl_register_mc_group(struct genl_family *family,
                mc_groups_longs++;
        }
 
-       err = netlink_change_ngroups(genl_sock,
-                                    mc_groups_longs * BITS_PER_LONG);
-       if (err)
-               goto out;
+       if (family->netnsok) {
+               struct net *net;
+
+               rcu_read_lock();
+               for_each_net_rcu(net) {
+                       err = netlink_change_ngroups(net->genl_sock,
+                                       mc_groups_longs * BITS_PER_LONG);
+                       if (err) {
+                               /*
+                                * No need to roll back, can only fail if
+                                * memory allocation fails and then the
+                                * number of _possible_ groups has been
+                                * increased on some sockets which is ok.
+                                */
+                               rcu_read_unlock();
+                               goto out;
+                       }
+               }
+               rcu_read_unlock();
+       } else {
+               err = netlink_change_ngroups(init_net.genl_sock,
+                                            mc_groups_longs * BITS_PER_LONG);
+               if (err)
+                       goto out;
+       }
 
        grp->id = id;
        set_bit(id, mc_groups);
@@ -195,8 +214,14 @@ EXPORT_SYMBOL(genl_register_mc_group);
 static void __genl_unregister_mc_group(struct genl_family *family,
                                       struct genl_multicast_group *grp)
 {
+       struct net *net;
        BUG_ON(grp->family != family);
-       netlink_clear_multicast_users(genl_sock, grp->id);
+
+       rcu_read_lock();
+       for_each_net_rcu(net)
+               netlink_clear_multicast_users(net->genl_sock, grp->id);
+       rcu_read_unlock();
+
        clear_bit(grp->id, mc_groups);
        list_del(&grp->list);
        genl_ctrl_event(CTRL_CMD_DELMCAST_GRP, grp);
@@ -467,6 +492,7 @@ static int genl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
 {
        struct genl_ops *ops;
        struct genl_family *family;
+       struct net *net = sock_net(skb->sk);
        struct genl_info info;
        struct genlmsghdr *hdr = nlmsg_data(nlh);
        int hdrlen, err;
@@ -475,6 +501,10 @@ static int genl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
        if (family == NULL)
                return -ENOENT;
 
+       /* this family doesn't exist in this netns */
+       if (!family->netnsok && !net_eq(net, &init_net))
+               return -ENOENT;
+
        hdrlen = GENL_HDRLEN + family->hdrsize;
        if (nlh->nlmsg_len < nlmsg_msg_size(hdrlen))
                return -EINVAL;
@@ -492,7 +522,7 @@ static int genl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
                        return -EOPNOTSUPP;
 
                genl_unlock();
-               err = netlink_dump_start(genl_sock, skb, nlh,
+               err = netlink_dump_start(net->genl_sock, skb, nlh,
                                         ops->dumpit, ops->done);
                genl_lock();
                return err;
@@ -514,6 +544,7 @@ static int genl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
        info.genlhdr = nlmsg_data(nlh);
        info.userhdr = nlmsg_data(nlh) + GENL_HDRLEN;
        info.attrs = family->attrbuf;
+       genl_info_net_set(&info, net);
 
        return ops->doit(skb, &info);
 }
@@ -534,6 +565,7 @@ static struct genl_family genl_ctrl = {
        .name = "nlctrl",
        .version = 0x2,
        .maxattr = CTRL_ATTR_MAX,
+       .netnsok = true,
 };
 
 static int ctrl_fill_info(struct genl_family *family, u32 pid, u32 seq,
@@ -650,6 +682,7 @@ static int ctrl_dumpfamily(struct sk_buff *skb, struct netlink_callback *cb)
 
        int i, n = 0;
        struct genl_family *rt;
+       struct net *net = sock_net(skb->sk);
        int chains_to_skip = cb->args[0];
        int fams_to_skip = cb->args[1];
 
@@ -658,6 +691,8 @@ static int ctrl_dumpfamily(struct sk_buff *skb, struct netlink_callback *cb)
                        continue;
                n = 0;
                list_for_each_entry(rt, genl_family_chain(i), family_list) {
+                       if (!rt->netnsok && !net_eq(net, &init_net))
+                               continue;
                        if (++n < fams_to_skip)
                                continue;
                        if (ctrl_fill_info(rt, NETLINK_CB(cb->skb).pid,
@@ -729,6 +764,7 @@ static int ctrl_getfamily(struct sk_buff *skb, struct genl_info *info)
        if (info->attrs[CTRL_ATTR_FAMILY_ID]) {
                u16 id = nla_get_u16(info->attrs[CTRL_ATTR_FAMILY_ID]);
                res = genl_family_find_byid(id);
+               err = -ENOENT;
        }
 
        if (info->attrs[CTRL_ATTR_FAMILY_NAME]) {
@@ -736,49 +772,61 @@ static int ctrl_getfamily(struct sk_buff *skb, struct genl_info *info)
 
                name = nla_data(info->attrs[CTRL_ATTR_FAMILY_NAME]);
                res = genl_family_find_byname(name);
+               err = -ENOENT;
        }
 
-       if (res == NULL) {
-               err = -ENOENT;
-               goto errout;
+       if (res == NULL)
+               return err;
+
+       if (!res->netnsok && !net_eq(genl_info_net(info), &init_net)) {
+               /* family doesn't exist here */
+               return -ENOENT;
        }
 
        msg = ctrl_build_family_msg(res, info->snd_pid, info->snd_seq,
                                    CTRL_CMD_NEWFAMILY);
-       if (IS_ERR(msg)) {
-               err = PTR_ERR(msg);
-               goto errout;
-       }
+       if (IS_ERR(msg))
+               return PTR_ERR(msg);
 
-       err = genlmsg_reply(msg, info);
-errout:
-       return err;
+       return genlmsg_reply(msg, info);
 }
 
 static int genl_ctrl_event(int event, void *data)
 {
        struct sk_buff *msg;
+       struct genl_family *family;
+       struct genl_multicast_group *grp;
 
-       if (genl_sock == NULL)
+       /* genl is still initialising */
+       if (!init_net.genl_sock)
                return 0;
 
        switch (event) {
        case CTRL_CMD_NEWFAMILY:
        case CTRL_CMD_DELFAMILY:
-               msg = ctrl_build_family_msg(data, 0, 0, event);
-               if (IS_ERR(msg))
-                       return PTR_ERR(msg);
-
-               genlmsg_multicast(msg, 0, GENL_ID_CTRL, GFP_KERNEL);
+               family = data;
+               msg = ctrl_build_family_msg(family, 0, 0, event);
                break;
        case CTRL_CMD_NEWMCAST_GRP:
        case CTRL_CMD_DELMCAST_GRP:
+               grp = data;
+               family = grp->family;
                msg = ctrl_build_mcgrp_msg(data, 0, 0, event);
-               if (IS_ERR(msg))
-                       return PTR_ERR(msg);
-
-               genlmsg_multicast(msg, 0, GENL_ID_CTRL, GFP_KERNEL);
                break;
+       default:
+               return -EINVAL;
+       }
+
+       if (IS_ERR(msg))
+               return PTR_ERR(msg);
+
+       if (!family->netnsok) {
+               genlmsg_multicast_netns(&init_net, msg, 0,
+                                       GENL_ID_CTRL, GFP_KERNEL);
+       } else {
+               rcu_read_lock();
+               genlmsg_multicast_allns(msg, 0, GENL_ID_CTRL, GFP_ATOMIC);
+               rcu_read_unlock();
        }
 
        return 0;
@@ -795,6 +843,33 @@ static struct genl_multicast_group notify_grp = {
        .name           = "notify",
 };
 
+static int __net_init genl_pernet_init(struct net *net)
+{
+       /* we'll bump the group number right afterwards */
+       net->genl_sock = netlink_kernel_create(net, NETLINK_GENERIC, 0,
+                                              genl_rcv, &genl_mutex,
+                                              THIS_MODULE);
+
+       if (!net->genl_sock && net_eq(net, &init_net))
+               panic("GENL: Cannot initialize generic netlink\n");
+
+       if (!net->genl_sock)
+               return -ENOMEM;
+
+       return 0;
+}
+
+static void __net_exit genl_pernet_exit(struct net *net)
+{
+       netlink_kernel_release(net->genl_sock);
+       net->genl_sock = NULL;
+}
+
+static struct pernet_operations genl_pernet_ops = {
+       .init = genl_pernet_init,
+       .exit = genl_pernet_exit,
+};
+
 static int __init genl_init(void)
 {
        int i, err;
@@ -804,36 +879,67 @@ static int __init genl_init(void)
 
        err = genl_register_family(&genl_ctrl);
        if (err < 0)
-               goto errout;
+               goto problem;
 
        err = genl_register_ops(&genl_ctrl, &genl_ctrl_ops);
        if (err < 0)
-               goto errout_register;
+               goto problem;
 
        netlink_set_nonroot(NETLINK_GENERIC, NL_NONROOT_RECV);
 
-       /* we'll bump the group number right afterwards */
-       genl_sock = netlink_kernel_create(&init_net, NETLINK_GENERIC, 0,
-                                         genl_rcv, &genl_mutex, THIS_MODULE);
-       if (genl_sock == NULL)
-               panic("GENL: Cannot initialize generic netlink\n");
+       err = register_pernet_subsys(&genl_pernet_ops);
+       if (err)
+               goto problem;
 
        err = genl_register_mc_group(&genl_ctrl, &notify_grp);
        if (err < 0)
-               goto errout_register;
+               goto problem;
 
        return 0;
 
-errout_register:
-       genl_unregister_family(&genl_ctrl);
-errout:
+problem:
        panic("GENL: Cannot register controller: %d\n", err);
 }
 
 subsys_initcall(genl_init);
 
-EXPORT_SYMBOL(genl_sock);
 EXPORT_SYMBOL(genl_register_ops);
 EXPORT_SYMBOL(genl_unregister_ops);
 EXPORT_SYMBOL(genl_register_family);
 EXPORT_SYMBOL(genl_unregister_family);
+
+static int genlmsg_mcast(struct sk_buff *skb, u32 pid, unsigned long group,
+                        gfp_t flags)
+{
+       struct sk_buff *tmp;
+       struct net *net, *prev = NULL;
+       int err;
+
+       for_each_net_rcu(net) {
+               if (prev) {
+                       tmp = skb_clone(skb, flags);
+                       if (!tmp) {
+                               err = -ENOMEM;
+                               goto error;
+                       }
+                       err = nlmsg_multicast(prev->genl_sock, tmp,
+                                             pid, group, flags);
+                       if (err)
+                               goto error;
+               }
+
+               prev = net;
+       }
+
+       return nlmsg_multicast(prev->genl_sock, skb, pid, group, flags);
+ error:
+       kfree_skb(skb);
+       return err;
+}
+
+int genlmsg_multicast_allns(struct sk_buff *skb, u32 pid, unsigned int group,
+                           gfp_t flags)
+{
+       return genlmsg_mcast(skb, pid, group, flags);
+}
+EXPORT_SYMBOL(genlmsg_multicast_allns);
index 3513724..c7b7838 100644 (file)
@@ -177,13 +177,13 @@ static int nr_xmit(struct sk_buff *skb, struct net_device *dev)
        if (!nr_route_frame(skb, NULL)) {
                kfree_skb(skb);
                stats->tx_errors++;
-               return 0;
+               return NETDEV_TX_OK;
        }
 
        stats->tx_packets++;
        stats->tx_bytes += len;
 
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 static const struct header_ops nr_header_ops = {
index ebe5718..d3d52c6 100644 (file)
@@ -137,8 +137,7 @@ dev->hard_header == NULL (ll header is added by device, we cannot control it)
 
 /* Private packet socket structures. */
 
-struct packet_mclist
-{
+struct packet_mclist {
        struct packet_mclist    *next;
        int                     ifindex;
        int                     count;
@@ -149,8 +148,7 @@ struct packet_mclist
 /* identical to struct packet_mreq except it has
  * a longer address field.
  */
-struct packet_mreq_max
-{
+struct packet_mreq_max {
        int             mr_ifindex;
        unsigned short  mr_type;
        unsigned short  mr_alen;
@@ -162,7 +160,7 @@ static int packet_set_ring(struct sock *sk, struct tpacket_req *req,
                int closing, int tx_ring);
 
 struct packet_ring_buffer {
-       char *                  *pg_vec;
+       char                    **pg_vec;
        unsigned int            head;
        unsigned int            frames_per_block;
        unsigned int            frame_size;
@@ -239,7 +237,7 @@ static void __packet_set_status(struct packet_sock *po, void *frame, int status)
                flush_dcache_page(virt_to_page(&h.h2->tp_status));
                break;
        default:
-               printk(KERN_ERR "TPACKET version not supported\n");
+               pr_err("TPACKET version not supported\n");
                BUG();
        }
 
@@ -265,7 +263,7 @@ static int __packet_get_status(struct packet_sock *po, void *frame)
                flush_dcache_page(virt_to_page(&h.h2->tp_status));
                return h.h2->tp_status;
        default:
-               printk(KERN_ERR "TPACKET version not supported\n");
+               pr_err("TPACKET version not supported\n");
                BUG();
                return 0;
        }
@@ -327,7 +325,7 @@ static void packet_sock_destruct(struct sock *sk)
        WARN_ON(atomic_read(&sk->sk_wmem_alloc));
 
        if (!sock_flag(sk, SOCK_DEAD)) {
-               printk("Attempt to release alive packet socket: %p\n", sk);
+               pr_err("Attempt to release alive packet socket: %p\n", sk);
                return;
        }
 
@@ -339,7 +337,8 @@ static const struct proto_ops packet_ops;
 
 static const struct proto_ops packet_ops_spkt;
 
-static int packet_rcv_spkt(struct sk_buff *skb, struct net_device *dev,  struct packet_type *pt, struct net_device *orig_dev)
+static int packet_rcv_spkt(struct sk_buff *skb, struct net_device *dev,
+                          struct packet_type *pt, struct net_device *orig_dev)
 {
        struct sock *sk;
        struct sockaddr_pkt *spkt;
@@ -368,7 +367,8 @@ static int packet_rcv_spkt(struct sk_buff *skb, struct net_device *dev,  struct
        if (dev_net(dev) != sock_net(sk))
                goto out;
 
-       if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL)
+       skb = skb_share_check(skb, GFP_ATOMIC);
+       if (skb == NULL)
                goto oom;
 
        /* drop any routing info */
@@ -394,7 +394,7 @@ static int packet_rcv_spkt(struct sk_buff *skb, struct net_device *dev,  struct
         *      to prevent sockets using all the memory up.
         */
 
-       if (sock_queue_rcv_skb(sk,skb) == 0)
+       if (sock_queue_rcv_skb(sk, skb) == 0)
                return 0;
 
 out:
@@ -413,25 +413,23 @@ static int packet_sendmsg_spkt(struct kiocb *iocb, struct socket *sock,
                               struct msghdr *msg, size_t len)
 {
        struct sock *sk = sock->sk;
-       struct sockaddr_pkt *saddr=(struct sockaddr_pkt *)msg->msg_name;
+       struct sockaddr_pkt *saddr = (struct sockaddr_pkt *)msg->msg_name;
        struct sk_buff *skb;
        struct net_device *dev;
-       __be16 proto=0;
+       __be16 proto = 0;
        int err;
 
        /*
         *      Get and verify the address.
         */
 
-       if (saddr)
-       {
+       if (saddr) {
                if (msg->msg_namelen < sizeof(struct sockaddr))
-                       return(-EINVAL);
-               if (msg->msg_namelen==sizeof(struct sockaddr_pkt))
-                       proto=saddr->spkt_protocol;
-       }
-       else
-               return(-ENOTCONN);      /* SOCK_PACKET must be sent giving an address */
+                       return -EINVAL;
+               if (msg->msg_namelen == sizeof(struct sockaddr_pkt))
+                       proto = saddr->spkt_protocol;
+       } else
+               return -ENOTCONN;       /* SOCK_PACKET must be sent giving an address */
 
        /*
         *      Find the device first to size check it
@@ -448,8 +446,8 @@ static int packet_sendmsg_spkt(struct kiocb *iocb, struct socket *sock,
                goto out_unlock;
 
        /*
-        *      You may not queue a frame bigger than the mtu. This is the lowest level
-        *      raw protocol and you must do your own fragmentation at this level.
+        * You may not queue a frame bigger than the mtu. This is the lowest level
+        * raw protocol and you must do your own fragmentation at this level.
         */
 
        err = -EMSGSIZE;
@@ -460,9 +458,9 @@ static int packet_sendmsg_spkt(struct kiocb *iocb, struct socket *sock,
        skb = sock_wmalloc(sk, len + LL_RESERVED_SPACE(dev), 0, GFP_KERNEL);
 
        /*
-        *      If the write buffer is full, then tough. At this level the user gets to
-        *      deal with the problem - do your own algorithmic backoffs. That's far
-        *      more flexible.
+        * If the write buffer is full, then tough. At this level the user
+        * gets to deal with the problem - do your own algorithmic backoffs.
+        * That's far more flexible.
         */
 
        if (skb == NULL)
@@ -488,7 +486,7 @@ static int packet_sendmsg_spkt(struct kiocb *iocb, struct socket *sock,
        }
 
        /* Returns -EFAULT on error */
-       err = memcpy_fromiovec(skb_put(skb,len), msg->msg_iov, len);
+       err = memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len);
        skb->protocol = proto;
        skb->dev = dev;
        skb->priority = sk->sk_priority;
@@ -501,7 +499,7 @@ static int packet_sendmsg_spkt(struct kiocb *iocb, struct socket *sock,
 
        dev_queue_xmit(skb);
        dev_put(dev);
-       return(len);
+       return len;
 
 out_free:
        kfree_skb(skb);
@@ -537,12 +535,13 @@ static inline unsigned int run_filter(struct sk_buff *skb, struct sock *sk,
    we will not harm anyone.
  */
 
-static int packet_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev)
+static int packet_rcv(struct sk_buff *skb, struct net_device *dev,
+                     struct packet_type *pt, struct net_device *orig_dev)
 {
        struct sock *sk;
        struct sockaddr_ll *sll;
        struct packet_sock *po;
-       u8 * skb_head = skb->data;
+       u8 *skb_head = skb->data;
        int skb_len = skb->len;
        unsigned int snaplen, res;
 
@@ -648,7 +647,8 @@ drop:
 }
 
 #ifdef CONFIG_PACKET_MMAP
-static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev)
+static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev,
+                      struct packet_type *pt, struct net_device *orig_dev)
 {
        struct sock *sk;
        struct packet_sock *po;
@@ -658,7 +658,7 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, struct packe
                struct tpacket2_hdr *h2;
                void *raw;
        } h;
-       u8 * skb_head = skb->data;
+       u8 *skb_head = skb->data;
        int skb_len = skb->len;
        unsigned int snaplen, res;
        unsigned long status = TP_STATUS_LOSING|TP_STATUS_USER;
@@ -821,7 +821,7 @@ ring_is_full:
 static void tpacket_destruct_skb(struct sk_buff *skb)
 {
        struct packet_sock *po = pkt_sk(skb->sk);
-       void * ph;
+       void *ph;
 
        BUG_ON(skb == NULL);
 
@@ -836,9 +836,9 @@ static void tpacket_destruct_skb(struct sk_buff *skb)
        sock_wfree(skb);
 }
 
-static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff * skb,
-               void * frame, struct net_device *dev, int size_max,
-               __be16 proto, unsigned char * addr)
+static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff *skb,
+               void *frame, struct net_device *dev, int size_max,
+               __be16 proto, unsigned char *addr)
 {
        union {
                struct tpacket_hdr *h1;
@@ -867,8 +867,7 @@ static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff * skb,
                break;
        }
        if (unlikely(tp_len > size_max)) {
-               printk(KERN_ERR "packet size is too long (%d > %d)\n",
-                               tp_len, size_max);
+               pr_err("packet size is too long (%d > %d)\n", tp_len, size_max);
                return -EMSGSIZE;
        }
 
@@ -883,12 +882,11 @@ static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff * skb,
                                NULL, tp_len);
                if (unlikely(err < 0))
                        return -EINVAL;
-       } else if (dev->hard_header_len ) {
+       } else if (dev->hard_header_len) {
                /* net device doesn't like empty head */
                if (unlikely(tp_len <= dev->hard_header_len)) {
-                       printk(KERN_ERR "packet size is too short "
-                                       "(%d < %d)\n", tp_len,
-                                       dev->hard_header_len);
+                       pr_err("packet size is too short (%d < %d)\n",
+                              tp_len, dev->hard_header_len);
                        return -EINVAL;
                }
 
@@ -917,9 +915,8 @@ static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff * skb,
                nr_frags = skb_shinfo(skb)->nr_frags;
 
                if (unlikely(nr_frags >= MAX_SKB_FRAGS)) {
-                       printk(KERN_ERR "Packet exceed the number "
-                                       "of skb frags(%lu)\n",
-                                       MAX_SKB_FRAGS);
+                       pr_err("Packet exceed the number of skb frags(%lu)\n",
+                              MAX_SKB_FRAGS);
                        return -EFAULT;
                }
 
@@ -944,8 +941,8 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg)
        struct net_device *dev;
        __be16 proto;
        int ifindex, err, reserve = 0;
-       void * ph;
-       struct sockaddr_ll *saddr=(struct sockaddr_ll *)msg->msg_name;
+       void *ph;
+       struct sockaddr_ll *saddr = (struct sockaddr_ll *)msg->msg_name;
        int tp_len, size_max;
        unsigned char *addr;
        int len_sum = 0;
@@ -1038,8 +1035,7 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg)
                        goto out_xmit;
                packet_increment_head(&po->tx_ring);
                len_sum += tp_len;
-       }
-       while (likely((ph != NULL) || ((!(msg->msg_flags & MSG_DONTWAIT))
+       } while (likely((ph != NULL) || ((!(msg->msg_flags & MSG_DONTWAIT))
                                        && (atomic_read(&po->tx_ring.pending))))
              );
 
@@ -1064,7 +1060,7 @@ static int packet_snd(struct socket *sock,
                          struct msghdr *msg, size_t len)
 {
        struct sock *sk = sock->sk;
-       struct sockaddr_ll *saddr=(struct sockaddr_ll *)msg->msg_name;
+       struct sockaddr_ll *saddr = (struct sockaddr_ll *)msg->msg_name;
        struct sk_buff *skb;
        struct net_device *dev;
        __be16 proto;
@@ -1110,7 +1106,7 @@ static int packet_snd(struct socket *sock,
 
        skb = sock_alloc_send_skb(sk, len + LL_ALLOCATED_SPACE(dev),
                                msg->msg_flags & MSG_DONTWAIT, &err);
-       if (skb==NULL)
+       if (skb == NULL)
                goto out_unlock;
 
        skb_reserve(skb, LL_RESERVED_SPACE(dev));
@@ -1122,7 +1118,7 @@ static int packet_snd(struct socket *sock,
                goto out_free;
 
        /* Returns -EFAULT on error */
-       err = memcpy_fromiovec(skb_put(skb,len), msg->msg_iov, len);
+       err = memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len);
        if (err)
                goto out_free;
 
@@ -1140,7 +1136,7 @@ static int packet_snd(struct socket *sock,
 
        dev_put(dev);
 
-       return(len);
+       return len;
 
 out_free:
        kfree_skb(skb);
@@ -1283,9 +1279,10 @@ out_unlock:
  *     Bind a packet socket to a device
  */
 
-static int packet_bind_spkt(struct socket *sock, struct sockaddr *uaddr, int addr_len)
+static int packet_bind_spkt(struct socket *sock, struct sockaddr *uaddr,
+                           int addr_len)
 {
-       struct sock *sk=sock->sk;
+       struct sock *sk = sock->sk;
        char name[15];
        struct net_device *dev;
        int err = -ENODEV;
@@ -1296,7 +1293,7 @@ static int packet_bind_spkt(struct socket *sock, struct sockaddr *uaddr, int add
 
        if (addr_len != sizeof(struct sockaddr))
                return -EINVAL;
-       strlcpy(name,uaddr->sa_data,sizeof(name));
+       strlcpy(name, uaddr->sa_data, sizeof(name));
 
        dev = dev_get_by_name(sock_net(sk), name);
        if (dev) {
@@ -1308,8 +1305,8 @@ static int packet_bind_spkt(struct socket *sock, struct sockaddr *uaddr, int add
 
 static int packet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
 {
-       struct sockaddr_ll *sll = (struct sockaddr_ll*)uaddr;
-       struct sock *sk=sock->sk;
+       struct sockaddr_ll *sll = (struct sockaddr_ll *)uaddr;
+       struct sock *sk = sock->sk;
        struct net_device *dev = NULL;
        int err;
 
@@ -1404,7 +1401,7 @@ static int packet_create(struct net *net, struct socket *sock, int protocol)
        sk_add_node(sk, &net->packet.sklist);
        sock_prot_inuse_add(net, &packet_proto, 1);
        write_unlock_bh(&net->packet.sklist_lock);
-       return(0);
+       return 0;
 out:
        return err;
 }
@@ -1441,7 +1438,7 @@ static int packet_recvmsg(struct kiocb *iocb, struct socket *sock,
         *      but then it will block.
         */
 
-       skb=skb_recv_datagram(sk,flags,flags&MSG_DONTWAIT,&err);
+       skb = skb_recv_datagram(sk, flags, flags & MSG_DONTWAIT, &err);
 
        /*
         *      An error occurred so return it. Because skb_recv_datagram()
@@ -1469,10 +1466,9 @@ static int packet_recvmsg(struct kiocb *iocb, struct socket *sock,
         */
 
        copied = skb->len;
-       if (copied > len)
-       {
-               copied=len;
-               msg->msg_flags|=MSG_TRUNC;
+       if (copied > len) {
+               copied = len;
+               msg->msg_flags |= MSG_TRUNC;
        }
 
        err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
@@ -1539,7 +1535,7 @@ static int packet_getname(struct socket *sock, struct sockaddr *uaddr,
        struct net_device *dev;
        struct sock *sk = sock->sk;
        struct packet_sock *po = pkt_sk(sk);
-       struct sockaddr_ll *sll = (struct sockaddr_ll*)uaddr;
+       struct sockaddr_ll *sll = (struct sockaddr_ll *)uaddr;
 
        if (peer)
                return -EOPNOTSUPP;
@@ -1584,14 +1580,15 @@ static int packet_dev_mc(struct net_device *dev, struct packet_mclist *i,
                else
                        return dev_unicast_delete(dev, i->addr);
                break;
-       default:;
+       default:
+               break;
        }
        return 0;
 }
 
 static void packet_dev_mclist(struct net_device *dev, struct packet_mclist *i, int what)
 {
-       for ( ; i; i=i->next) {
+       for ( ; i; i = i->next) {
                if (i->ifindex == dev->ifindex)
                        packet_dev_mc(dev, i, what);
        }
@@ -1693,7 +1690,8 @@ static void packet_flush_mclist(struct sock *sk)
                struct net_device *dev;
 
                po->mclist = ml->next;
-               if ((dev = dev_get_by_index(sock_net(sk), ml->ifindex)) != NULL) {
+               dev = dev_get_by_index(sock_net(sk), ml->ifindex);
+               if (dev != NULL) {
                        packet_dev_mc(dev, ml, -1);
                        dev_put(dev);
                }
@@ -1723,7 +1721,7 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv
                        return -EINVAL;
                if (len > sizeof(mreq))
                        len = sizeof(mreq);
-               if (copy_from_user(&mreq,optval,len))
+               if (copy_from_user(&mreq, optval, len))
                        return -EFAULT;
                if (len < (mreq.mr_alen + offsetof(struct packet_mreq, mr_address)))
                        return -EINVAL;
@@ -1740,9 +1738,9 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv
        {
                struct tpacket_req req;
 
-               if (optlen<sizeof(req))
+               if (optlen < sizeof(req))
                        return -EINVAL;
-               if (copy_from_user(&req,optval,sizeof(req)))
+               if (copy_from_user(&req, optval, sizeof(req)))
                        return -EFAULT;
                return packet_set_ring(sk, &req, 0, optname == PACKET_TX_RING);
        }
@@ -1750,9 +1748,9 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv
        {
                int val;
 
-               if (optlen!=sizeof(val))
+               if (optlen != sizeof(val))
                        return -EINVAL;
-               if (copy_from_user(&val,optval,sizeof(val)))
+               if (copy_from_user(&val, optval, sizeof(val)))
                        return -EFAULT;
 
                pkt_sk(sk)->copy_thresh = val;
@@ -1985,51 +1983,51 @@ static int packet_ioctl(struct socket *sock, unsigned int cmd,
        struct sock *sk = sock->sk;
 
        switch (cmd) {
-               case SIOCOUTQ:
-               {
-                       int amount = sk_wmem_alloc_get(sk);
+       case SIOCOUTQ:
+       {
+               int amount = sk_wmem_alloc_get(sk);
 
-                       return put_user(amount, (int __user *)arg);
-               }
-               case SIOCINQ:
-               {
-                       struct sk_buff *skb;
-                       int amount = 0;
-
-                       spin_lock_bh(&sk->sk_receive_queue.lock);
-                       skb = skb_peek(&sk->sk_receive_queue);
-                       if (skb)
-                               amount = skb->len;
-                       spin_unlock_bh(&sk->sk_receive_queue.lock);
-                       return put_user(amount, (int __user *)arg);
-               }
-               case SIOCGSTAMP:
-                       return sock_get_timestamp(sk, (struct timeval __user *)arg);
-               case SIOCGSTAMPNS:
-                       return sock_get_timestampns(sk, (struct timespec __user *)arg);
+               return put_user(amount, (int __user *)arg);
+       }
+       case SIOCINQ:
+       {
+               struct sk_buff *skb;
+               int amount = 0;
+
+               spin_lock_bh(&sk->sk_receive_queue.lock);
+               skb = skb_peek(&sk->sk_receive_queue);
+               if (skb)
+                       amount = skb->len;
+               spin_unlock_bh(&sk->sk_receive_queue.lock);
+               return put_user(amount, (int __user *)arg);
+       }
+       case SIOCGSTAMP:
+               return sock_get_timestamp(sk, (struct timeval __user *)arg);
+       case SIOCGSTAMPNS:
+               return sock_get_timestampns(sk, (struct timespec __user *)arg);
 
 #ifdef CONFIG_INET
-               case SIOCADDRT:
-               case SIOCDELRT:
-               case SIOCDARP:
-               case SIOCGARP:
-               case SIOCSARP:
-               case SIOCGIFADDR:
-               case SIOCSIFADDR:
-               case SIOCGIFBRDADDR:
-               case SIOCSIFBRDADDR:
-               case SIOCGIFNETMASK:
-               case SIOCSIFNETMASK:
-               case SIOCGIFDSTADDR:
-               case SIOCSIFDSTADDR:
-               case SIOCSIFFLAGS:
-                       if (!net_eq(sock_net(sk), &init_net))
-                               return -ENOIOCTLCMD;
-                       return inet_dgram_ops.ioctl(sock, cmd, arg);
+       case SIOCADDRT:
+       case SIOCDELRT:
+       case SIOCDARP:
+       case SIOCGARP:
+       case SIOCSARP:
+       case SIOCGIFADDR:
+       case SIOCSIFADDR:
+       case SIOCGIFBRDADDR:
+       case SIOCSIFBRDADDR:
+       case SIOCGIFNETMASK:
+       case SIOCSIFNETMASK:
+       case SIOCGIFDSTADDR:
+       case SIOCSIFDSTADDR:
+       case SIOCSIFFLAGS:
+               if (!net_eq(sock_net(sk), &init_net))
+                       return -ENOIOCTLCMD;
+               return inet_dgram_ops.ioctl(sock, cmd, arg);
 #endif
 
-               default:
-                       return -ENOIOCTLCMD;
+       default:
+               return -ENOIOCTLCMD;
        }
        return 0;
 }
@@ -2039,7 +2037,7 @@ static int packet_ioctl(struct socket *sock, unsigned int cmd,
 #define packet_poll datagram_poll
 #else
 
-static unsigned int packet_poll(struct file * file, struct socket *sock,
+static unsigned int packet_poll(struct file *file, struct socket *sock,
                                poll_table *wait)
 {
        struct sock *sk = sock->sk;
@@ -2069,7 +2067,7 @@ static unsigned int packet_poll(struct file * file, struct socket *sock,
 static void packet_mm_open(struct vm_area_struct *vma)
 {
        struct file *file = vma->vm_file;
-       struct socket * sock = file->private_data;
+       struct socket *sock = file->private_data;
        struct sock *sk = sock->sk;
 
        if (sk)
@@ -2079,7 +2077,7 @@ static void packet_mm_open(struct vm_area_struct *vma)
 static void packet_mm_close(struct vm_area_struct *vma)
 {
        struct file *file = vma->vm_file;
-       struct socket * sock = file->private_data;
+       struct socket *sock = file->private_data;
        struct sock *sk = sock->sk;
 
        if (sk)
@@ -2087,8 +2085,8 @@ static void packet_mm_close(struct vm_area_struct *vma)
 }
 
 static struct vm_operations_struct packet_mmap_ops = {
-       .open = packet_mm_open,
-       .close =packet_mm_close,
+       .open   =       packet_mm_open,
+       .close  =       packet_mm_close,
 };
 
 static void free_pg_vec(char **pg_vec, unsigned int order, unsigned int len)
@@ -2239,8 +2237,8 @@ static int packet_set_ring(struct sock *sk, struct tpacket_req *req,
                skb_queue_purge(rb_queue);
 #undef XC
                if (atomic_read(&po->mapped))
-                       printk(KERN_DEBUG "packet_mmap: vma is busy: %d\n",
-                                               atomic_read(&po->mapped));
+                       pr_err("packet_mmap: vma is busy: %d\n",
+                              atomic_read(&po->mapped));
        }
        mutex_unlock(&po->pg_vec_lock);
 
@@ -2303,7 +2301,7 @@ static int packet_mmap(struct file *file, struct socket *sock,
                        int pg_num;
 
                        for (pg_num = 0; pg_num < rb->pg_vec_pages;
-                                       pg_num++,page++) {
+                                       pg_num++, page++) {
                                err = vm_insert_page(vma, start, page);
                                if (unlikely(err))
                                        goto out;
@@ -2372,7 +2370,7 @@ static struct net_proto_family packet_family_ops = {
 };
 
 static struct notifier_block packet_netdev_notifier = {
-       .notifier_call =packet_notifier,
+       .notifier_call =        packet_notifier,
 };
 
 #ifdef CONFIG_PROC_FS
@@ -2402,7 +2400,7 @@ static void *packet_seq_next(struct seq_file *seq, void *v, loff_t *pos)
        ++*pos;
        return  (v == SEQ_START_TOKEN)
                ? sk_head(&net->packet.sklist)
-               : sk_next((struct sock*)v) ;
+               : sk_next((struct sock *)v) ;
 }
 
 static void packet_seq_stop(struct seq_file *seq, void *v)
@@ -2430,7 +2428,7 @@ static int packet_seq_show(struct seq_file *seq, void *v)
                           po->running,
                           atomic_read(&s->sk_rmem_alloc),
                           sock_i_uid(s),
-                          sock_i_ino(s) );
+                          sock_i_ino(s));
        }
 
        return 0;
index e087862..ef5c75c 100644 (file)
@@ -159,8 +159,11 @@ out_nofree:
 static int pn_backlog_rcv(struct sock *sk, struct sk_buff *skb)
 {
        int err = sock_queue_rcv_skb(sk, skb);
-       if (err < 0)
+       if (err < 0) {
                kfree_skb(skb);
+               if (err == -ENOMEM)
+                       atomic_inc(&sk->sk_drops);
+       }
        return err ? NET_RX_DROP : NET_RX_SUCCESS;
 }
 
index 480839d..4667af5 100644 (file)
@@ -195,7 +195,7 @@ static int gprs_xmit(struct sk_buff *skb, struct net_device *dev)
                break;
        default:
                dev_kfree_skb(skb);
-               return 0;
+               return NETDEV_TX_OK;
        }
 
        skb_orphan(skb);
@@ -215,7 +215,7 @@ static int gprs_xmit(struct sk_buff *skb, struct net_device *dev)
        netif_stop_queue(dev);
        if (pep_writeable(sk))
                netif_wake_queue(dev);
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 static int gprs_set_mtu(struct net_device *dev, int new_mtu)
index eef833e..b8252d2 100644 (file)
@@ -346,8 +346,10 @@ static int pipe_do_rcv(struct sock *sk, struct sk_buff *skb)
                break;
 
        case PNS_PEP_CTRL_REQ:
-               if (skb_queue_len(&pn->ctrlreq_queue) >= PNPIPE_CTRLREQ_MAX)
+               if (skb_queue_len(&pn->ctrlreq_queue) >= PNPIPE_CTRLREQ_MAX) {
+                       atomic_inc(&sk->sk_drops);
                        break;
+               }
                __skb_pull(skb, 4);
                queue = &pn->ctrlreq_queue;
                goto queue;
@@ -358,10 +360,13 @@ static int pipe_do_rcv(struct sock *sk, struct sk_buff *skb)
                        err = sock_queue_rcv_skb(sk, skb);
                        if (!err)
                                return 0;
+                       if (err == -ENOMEM)
+                               atomic_inc(&sk->sk_drops);
                        break;
                }
 
                if (pn->rx_credits == 0) {
+                       atomic_inc(&sk->sk_drops);
                        err = -ENOBUFS;
                        break;
                }
index b0d6ddd..5107b79 100644 (file)
@@ -218,6 +218,11 @@ static int phonet_init_net(struct net *net)
        if (!pnn)
                return -ENOMEM;
 
+       if (!proc_net_fops_create(net, "phonet", 0, &pn_sock_seq_fops)) {
+               kfree(pnn);
+               return -ENOMEM;
+       }
+
        INIT_LIST_HEAD(&pnn->pndevs.list);
        spin_lock_init(&pnn->pndevs.lock);
        net_assign_generic(net, phonet_net_id, pnn);
@@ -233,6 +238,8 @@ static void phonet_exit_net(struct net *net)
        for_each_netdev(net, dev)
                phonet_device_destroy(dev);
        rtnl_unlock();
+
+       proc_net_remove(net, "phonet");
        kfree(pnn);
 }
 
index ada2a35..aa1617a 100644 (file)
@@ -412,3 +412,99 @@ found:
        return 0;
 }
 EXPORT_SYMBOL(pn_sock_get_port);
+
+static struct sock *pn_sock_get_idx(struct seq_file *seq, loff_t pos)
+{
+       struct net *net = seq_file_net(seq);
+       struct hlist_node *node;
+       struct sock *sknode;
+
+       sk_for_each(sknode, node, &pnsocks.hlist) {
+               if (!net_eq(net, sock_net(sknode)))
+                       continue;
+               if (!pos)
+                       return sknode;
+               pos--;
+       }
+       return NULL;
+}
+
+static struct sock *pn_sock_get_next(struct seq_file *seq, struct sock *sk)
+{
+       struct net *net = seq_file_net(seq);
+
+       do
+               sk = sk_next(sk);
+       while (sk && !net_eq(net, sock_net(sk)));
+
+       return sk;
+}
+
+static void *pn_sock_seq_start(struct seq_file *seq, loff_t *pos)
+       __acquires(pnsocks.lock)
+{
+       spin_lock_bh(&pnsocks.lock);
+       return *pos ? pn_sock_get_idx(seq, *pos - 1) : SEQ_START_TOKEN;
+}
+
+static void *pn_sock_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+       struct sock *sk;
+
+       if (v == SEQ_START_TOKEN)
+               sk = pn_sock_get_idx(seq, 0);
+       else
+               sk = pn_sock_get_next(seq, v);
+       (*pos)++;
+       return sk;
+}
+
+static void pn_sock_seq_stop(struct seq_file *seq, void *v)
+       __releases(pnsocks.lock)
+{
+       spin_unlock_bh(&pnsocks.lock);
+}
+
+static int pn_sock_seq_show(struct seq_file *seq, void *v)
+{
+       int len;
+
+       if (v == SEQ_START_TOKEN)
+               seq_printf(seq, "%s%n", "pt  loc  rem rs st tx_queue rx_queue "
+                       "  uid inode ref pointer drops", &len);
+       else {
+               struct sock *sk = v;
+               struct pn_sock *pn = pn_sk(sk);
+
+               seq_printf(seq, "%2d %04X:%04X:%02X %02X %08X:%08X %5d %lu "
+                       "%d %p %d%n",
+                       sk->sk_protocol, pn->sobject, 0, pn->resource,
+                       sk->sk_state,
+                       sk_wmem_alloc_get(sk), sk_rmem_alloc_get(sk),
+                       sock_i_uid(sk), sock_i_ino(sk),
+                       atomic_read(&sk->sk_refcnt), sk,
+                       atomic_read(&sk->sk_drops), &len);
+       }
+       seq_printf(seq, "%*s\n", 127 - len, "");
+       return 0;
+}
+
+static const struct seq_operations pn_sock_seq_ops = {
+       .start = pn_sock_seq_start,
+       .next = pn_sock_seq_next,
+       .stop = pn_sock_seq_stop,
+       .show = pn_sock_seq_show,
+};
+
+static int pn_sock_open(struct inode *inode, struct file *file)
+{
+       return seq_open(file, &pn_sock_seq_ops);
+}
+
+const struct file_operations pn_sock_seq_fops = {
+       .owner = THIS_MODULE,
+       .open = pn_sock_open,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = seq_release,
+};
index d14445c..b420a20 100644 (file)
@@ -126,7 +126,7 @@ 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 rds_connection *conn, *parent = NULL;
        struct hlist_head *head = rds_conn_bucket(laddr, faddr);
        unsigned long flags;
        int ret;
@@ -155,7 +155,6 @@ static struct rds_connection *__rds_conn_create(__be32 laddr, __be32 faddr,
        }
 
        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);
@@ -211,26 +210,40 @@ static struct rds_connection *__rds_conn_create(__be32 laddr, __be32 faddr,
          trans->t_name ? trans->t_name : "[unknown]",
          is_outgoing ? "(outgoing)" : "");
 
+       /*
+        * Since we ran without holding the conn lock, someone could
+        * have created the same conn (either normal or passive) in the
+        * interim. We check while holding the lock. If we won, we complete
+        * init and return our conn. If we lost, we rollback and return the
+        * other one.
+        */
        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)
+       if (parent) {
+               /* Creating passive conn */
+               if (parent->c_passive) {
+                       trans->conn_free(conn->c_transport_data);
+                       kmem_cache_free(rds_conn_slab, conn);
+                       conn = parent->c_passive;
+               } else {
                        parent->c_passive = conn;
-       }
-
-       if (tmp) {
-               trans->conn_free(conn->c_transport_data);
-               kmem_cache_free(rds_conn_slab, conn);
-               conn = tmp;
+                       rds_cong_add_conn(conn);
+                       rds_conn_count++;
+               }
        } else {
-               rds_cong_add_conn(conn);
-               rds_conn_count++;
+               /* Creating normal conn */
+               struct rds_connection *found;
+
+               found = rds_conn_lookup(head, laddr, faddr, trans);
+               if (found) {
+                       trans->conn_free(conn->c_transport_data);
+                       kmem_cache_free(rds_conn_slab, conn);
+                       conn = found;
+               } else {
+                       hlist_add_head(&conn->c_hash_node, head);
+                       rds_cong_add_conn(conn);
+                       rds_conn_count++;
+               }
        }
-
        spin_unlock_irqrestore(&rds_conn_lock, flags);
 
 out:
index b9bcd32..868559a 100644 (file)
 
 unsigned int fmr_pool_size = RDS_FMR_POOL_SIZE;
 unsigned int fmr_message_size = RDS_FMR_SIZE + 1; /* +1 allows for unaligned MRs */
+unsigned int rds_ib_retry_count = RDS_IB_DEFAULT_RETRY_COUNT;
 
 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");
+module_param(rds_ib_retry_count, int, 0444);
+MODULE_PARM_DESC(rds_ib_retry_count, " Number of hw retries before reporting an error");
 
 struct list_head rds_ib_devices;
 
@@ -82,9 +85,6 @@ void rds_ib_add_one(struct ib_device *device)
        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) :
index 455ae73..1378b85 100644 (file)
@@ -15,6 +15,8 @@
 #define RDS_IB_DEFAULT_RECV_WR         1024
 #define RDS_IB_DEFAULT_SEND_WR         256
 
+#define RDS_IB_DEFAULT_RETRY_COUNT     2
+
 #define RDS_IB_SUPPORTED_PROTOCOLS     0x00000003      /* minor versions supported */
 
 extern struct list_head rds_ib_devices;
@@ -157,9 +159,6 @@ struct rds_ib_device {
        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;
@@ -247,6 +246,7 @@ extern struct ib_client rds_ib_client;
 
 extern unsigned int fmr_pool_size;
 extern unsigned int fmr_message_size;
+extern unsigned int rds_ib_retry_count;
 
 extern spinlock_t ib_nodev_conns_lock;
 extern struct list_head ib_nodev_conns;
@@ -355,17 +355,25 @@ extern ctl_table rds_ib_sysctl_table[];
 /*
  * Helper functions for getting/setting the header and data SGEs in
  * RDS packets (not RDMA)
+ *
+ * From version 3.1 onwards, header is in front of data in the sge.
  */
 static inline struct ib_sge *
 rds_ib_header_sge(struct rds_ib_connection *ic, struct ib_sge *sge)
 {
-       return &sge[0];
+       if (ic->conn->c_version > RDS_PROTOCOL_3_0)
+               return &sge[0];
+       else
+               return &sge[1];
 }
 
 static inline struct ib_sge *
 rds_ib_data_sge(struct rds_ib_connection *ic, struct ib_sge *sge)
 {
-       return &sge[1];
+       if (ic->conn->c_version > RDS_PROTOCOL_3_0)
+               return &sge[1];
+       else
+               return &sge[0];
 }
 
 #endif
index f8e40e1..c2d372f 100644 (file)
@@ -98,21 +98,34 @@ void rds_ib_cm_connect_complete(struct rds_connection *conn, struct rdma_cm_even
        struct ib_qp_attr qp_attr;
        int err;
 
-       if (event->param.conn.private_data_len) {
+       if (event->param.conn.private_data_len >= sizeof(*dp)) {
                dp = event->param.conn.private_data;
 
-               rds_ib_set_protocol(conn,
+               /* make sure it isn't empty data */
+               if (dp->dp_protocol_major) {
+                       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));
+                               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,
+                       &conn->c_faddr,
                        RDS_PROTOCOL_MAJOR(conn->c_version),
                        RDS_PROTOCOL_MINOR(conn->c_version),
                        ic->i_flowctl ? ", flow control" : "");
 
+       /*
+        * Init rings and fill recv. this needs to wait until protocol negotiation
+        * is complete, since ring layout is different from 3.0 to 3.1.
+        */
+       rds_ib_send_init_ring(ic);
+       rds_ib_recv_init_ring(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);
+
        /* Tune RNR behavior */
        rds_ib_tune_rnr(ic, &qp_attr);
 
@@ -145,7 +158,7 @@ static void rds_ib_cm_fill_conn_param(struct rds_connection *conn,
        /* XXX tune these? */
        conn_param->responder_resources = 1;
        conn_param->initiator_depth = 1;
-       conn_param->retry_count = 7;
+       conn_param->retry_count = min_t(unsigned int, rds_ib_retry_count, 7);
        conn_param->rnr_retry_count = 7;
 
        if (dp) {
@@ -190,9 +203,9 @@ static void rds_ib_qp_event_handler(struct ib_event *event, void *data)
                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);
+               rds_ib_conn_error(conn, "RDS/IB: Fatal QP Event %u "
+                       "- connection %pI4->%pI4, reconnecting\n",
+                       event->event, &conn->c_laddr, &conn->c_faddr);
                break;
        }
 }
@@ -321,7 +334,7 @@ static int rds_ib_setup_qp(struct rds_connection *conn)
                rdsdebug("send allocation failed\n");
                goto out;
        }
-       rds_ib_send_init_ring(ic);
+       memset(ic->i_sends, 0, ic->i_send_ring.w_nr * sizeof(struct rds_ib_send_work));
 
        ic->i_recvs = vmalloc(ic->i_recv_ring.w_nr * sizeof(struct rds_ib_recv_work));
        if (ic->i_recvs == NULL) {
@@ -329,14 +342,10 @@ static int rds_ib_setup_qp(struct rds_connection *conn)
                rdsdebug("recv allocation failed\n");
                goto out;
        }
+       memset(ic->i_recvs, 0, ic->i_recv_ring.w_nr * sizeof(struct rds_ib_recv_work));
 
-       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);
 
@@ -344,19 +353,32 @@ out:
        return ret;
 }
 
-static u32 rds_ib_protocol_compatible(const struct rds_ib_connect_private *dp)
+static u32 rds_ib_protocol_compatible(struct rdma_cm_event *event)
 {
+       const struct rds_ib_connect_private *dp = event->param.conn.private_data;
        u16 common;
        u32 version = 0;
 
-       /* rdma_cm private data is odd - when there is any private data in the
+       /*
+        * 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)
+        * We really should have changed this for OFED 1.3 :-(
+        */
+
+       /* Be paranoid. RDS always has privdata */
+       if (!event->param.conn.private_data_len) {
+               printk(KERN_NOTICE "RDS incoming connection has no private data, "
+                       "rejecting\n");
+               return 0;
+       }
+
+       /* Even if len is crap *now* I still want to check it. -ASG */
+       if (event->param.conn.private_data_len < sizeof (*dp)
+           || dp->dp_protocol_major == 0)
                return RDS_PROTOCOL_3_0;
 
        common = be16_to_cpu(dp->dp_protocol_minor_mask) & RDS_IB_SUPPORTED_PROTOCOLS;
@@ -388,7 +410,7 @@ int rds_ib_cm_handle_connect(struct rdma_cm_id *cm_id,
        int err, destroy = 1;
 
        /* Check whether the remote protocol version matches ours. */
-       version = rds_ib_protocol_compatible(dp);
+       version = rds_ib_protocol_compatible(event);
        if (!version)
                goto out;
 
index 81033af..ef3ab5b 100644 (file)
@@ -211,7 +211,7 @@ struct rds_ib_mr_pool *rds_ib_create_mr_pool(struct rds_ib_device *rds_ibdev)
 
        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->fmr_attr.page_shift = 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.
@@ -349,13 +349,13 @@ static int rds_ib_map_fmr(struct rds_ib_device *rds_ibdev, struct rds_ib_mr *ibm
                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 (dma_addr & ~PAGE_MASK) {
                        if (i > 0)
                                return -EINVAL;
                        else
                                ++page_cnt;
                }
-               if ((dma_addr + dma_len) & ~rds_ibdev->fmr_page_mask) {
+               if ((dma_addr + dma_len) & ~PAGE_MASK) {
                        if (i < sg_dma_len - 1)
                                return -EINVAL;
                        else
@@ -365,7 +365,7 @@ static int rds_ib_map_fmr(struct rds_ib_device *rds_ibdev, struct rds_ib_mr *ibm
                len += dma_len;
        }
 
-       page_cnt += len >> rds_ibdev->fmr_page_shift;
+       page_cnt += len >> PAGE_SHIFT;
        if (page_cnt > fmr_message_size)
                return -EINVAL;
 
@@ -378,9 +378,9 @@ static int rds_ib_map_fmr(struct rds_ib_device *rds_ibdev, struct rds_ib_mr *ibm
                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)
+               for (j = 0; j < dma_len; j += PAGE_SIZE)
                        dma_pages[page_cnt++] =
-                               (dma_addr & rds_ibdev->fmr_page_mask) + j;
+                               (dma_addr & PAGE_MASK) + j;
        }
 
        ret = ib_map_phys_fmr(ibmr->fmr,
index 5709bad..cd7a6cf 100644 (file)
@@ -555,6 +555,47 @@ u64 rds_ib_piggyb_ack(struct rds_ib_connection *ic)
        return rds_ib_get_ack(ic);
 }
 
+static struct rds_header *rds_ib_get_header(struct rds_connection *conn,
+                                           struct rds_ib_recv_work *recv,
+                                           u32 data_len)
+{
+       struct rds_ib_connection *ic = conn->c_transport_data;
+       void *hdr_buff = &ic->i_recv_hdrs[recv - ic->i_recvs];
+       void *addr;
+       u32 misplaced_hdr_bytes;
+
+       /*
+        * Support header at the front (RDS 3.1+) as well as header-at-end.
+        *
+        * Cases:
+        * 1) header all in header buff (great!)
+        * 2) header all in data page (copy all to header buff)
+        * 3) header split across hdr buf + data page
+        *    (move bit in hdr buff to end before copying other bit from data page)
+        */
+       if (conn->c_version > RDS_PROTOCOL_3_0 || data_len == RDS_FRAG_SIZE)
+               return hdr_buff;
+
+       if (data_len <= (RDS_FRAG_SIZE - sizeof(struct rds_header))) {
+               addr = kmap_atomic(recv->r_frag->f_page, KM_SOFTIRQ0);
+               memcpy(hdr_buff,
+                      addr + recv->r_frag->f_offset + data_len,
+                      sizeof(struct rds_header));
+               kunmap_atomic(addr, KM_SOFTIRQ0);
+               return hdr_buff;
+       }
+
+       misplaced_hdr_bytes = (sizeof(struct rds_header) - (RDS_FRAG_SIZE - data_len));
+
+       memmove(hdr_buff + misplaced_hdr_bytes, hdr_buff, misplaced_hdr_bytes);
+
+       addr = kmap_atomic(recv->r_frag->f_page, KM_SOFTIRQ0);
+       memcpy(hdr_buff, addr + recv->r_frag->f_offset + data_len,
+              sizeof(struct rds_header) - misplaced_hdr_bytes);
+       kunmap_atomic(addr, KM_SOFTIRQ0);
+       return hdr_buff;
+}
+
 /*
  * 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
@@ -645,7 +686,7 @@ struct rds_ib_ack_state {
 };
 
 static void rds_ib_process_recv(struct rds_connection *conn,
-                               struct rds_ib_recv_work *recv, u32 byte_len,
+                               struct rds_ib_recv_work *recv, u32 data_len,
                                struct rds_ib_ack_state *state)
 {
        struct rds_ib_connection *ic = conn->c_transport_data;
@@ -655,9 +696,9 @@ static void rds_ib_process_recv(struct rds_connection *conn,
        /* 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);
+                data_len);
 
-       if (byte_len < sizeof(struct rds_header)) {
+       if (data_len < sizeof(struct rds_header)) {
                rds_ib_conn_error(conn, "incoming message "
                       "from %pI4 didn't inclue a "
                       "header, disconnecting and "
@@ -665,9 +706,9 @@ static void rds_ib_process_recv(struct rds_connection *conn,
                       &conn->c_faddr);
                return;
        }
-       byte_len -= sizeof(struct rds_header);
+       data_len -= sizeof(struct rds_header);
 
-       ihdr = &ic->i_recv_hdrs[recv - ic->i_recvs];
+       ihdr = rds_ib_get_header(conn, recv, data_len);
 
        /* Validate the checksum. */
        if (!rds_message_verify_checksum(ihdr)) {
@@ -687,7 +728,7 @@ static void rds_ib_process_recv(struct rds_connection *conn,
        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) {
+       if (ihdr->h_sport == 0 && ihdr->h_dport == 0 && data_len == 0) {
                /* This is an ACK-only packet. The fact that it gets
                 * special treatment here is that historically, ACKs
                 * were rather special beasts.
index d87830d..84b5ffc 100644 (file)
@@ -53,7 +53,17 @@ 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;
+/*
+ * This sysctl does nothing.
+ *
+ * Backwards compatibility with RDS 3.0 wire protocol
+ * disables initial FC credit exchange.
+ * If it's ever possible to drop 3.0 support,
+ * setting this to 1 and moving init/refill of send/recv
+ * rings from ib_cm_connect_complete() back into ib_setup_qp()
+ * will cause credits to be added before protocol negotiation.
+ */
+unsigned int rds_ib_sysctl_flow_control = 0;
 
 ctl_table rds_ib_sysctl_table[] = {
        {
index d16e1cb..f5e9a29 100644 (file)
@@ -83,23 +83,16 @@ void rds_iw_add_one(struct ib_device *device)
        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);
-               }
+               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
index 0715dde..dd72b62 100644 (file)
@@ -181,7 +181,6 @@ struct rds_iw_device {
        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;
index dcdb37d..de4a1b1 100644 (file)
@@ -263,18 +263,12 @@ static void rds_iw_set_scatterlist(struct rds_iw_scatterlist *sg,
 }
 
 static u64 *rds_iw_map_scatterlist(struct rds_iw_device *rds_iwdev,
-                       struct rds_iw_scatterlist *sg,
-                       unsigned int dma_page_shift)
+                       struct rds_iw_scatterlist *sg)
 {
        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);
@@ -295,18 +289,18 @@ static u64 *rds_iw_map_scatterlist(struct rds_iw_device *rds_iwdev,
                sg->bytes += dma_len;
 
                end_addr = dma_addr + dma_len;
-               if (dma_addr & dma_mask) {
+               if (dma_addr & PAGE_MASK) {
                        if (i > 0)
                                goto out_unmap;
-                       dma_addr &= ~dma_mask;
+                       dma_addr &= ~PAGE_MASK;
                }
-               if (end_addr & dma_mask) {
+               if (end_addr & PAGE_MASK) {
                        if (i < sg->dma_len - 1)
                                goto out_unmap;
-                       end_addr = (end_addr + dma_mask) & ~dma_mask;
+                       end_addr = (end_addr + PAGE_MASK) & ~PAGE_MASK;
                }
 
-               sg->dma_npages += (end_addr - dma_addr) >> dma_page_shift;
+               sg->dma_npages += (end_addr - dma_addr) >> PAGE_SHIFT;
        }
 
        /* Now gather the dma addrs into one list */
@@ -325,8 +319,8 @@ static u64 *rds_iw_map_scatterlist(struct rds_iw_device *rds_iwdev,
                u64 end_addr;
 
                end_addr = dma_addr + dma_len;
-               dma_addr &= ~dma_mask;
-               for (; dma_addr < end_addr; dma_addr += dma_page_size)
+               dma_addr &= ~PAGE_MASK;
+               for (; dma_addr < end_addr; dma_addr += PAGE_SIZE)
                        dma_pages[j++] = dma_addr;
                BUG_ON(j > sg->dma_npages);
        }
@@ -727,7 +721,7 @@ static int rds_iw_rdma_build_fastreg(struct rds_iw_mapping *mapping)
        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.page_shift = PAGE_SHIFT;
        f_wr.wr.fast_reg.access_flags = IB_ACCESS_LOCAL_WRITE |
                                IB_ACCESS_REMOTE_READ |
                                IB_ACCESS_REMOTE_WRITE;
@@ -780,9 +774,7 @@ static int rds_iw_map_fastreg(struct rds_iw_mr_pool *pool,
 
        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);
+       dma_pages = rds_iw_map_scatterlist(rds_iwdev, &mapping->m_sg);
        if (IS_ERR(dma_pages)) {
                ret = PTR_ERR(dma_pages);
                dma_pages = NULL;
index 44a6a05..1f5abe3 100644 (file)
@@ -779,7 +779,7 @@ static void rds_iw_build_send_fastreg(struct rds_iw_device *rds_iwdev, struct rd
        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.page_shift = PAGE_SHIFT;
        send->s_wr.wr.fast_reg.access_flags = IB_ACCESS_REMOTE_WRITE;
        send->s_wr.wr.fast_reg.iova_start = sg_addr;
 
index 7d0f901..981a5e6 100644 (file)
@@ -101,7 +101,7 @@ int rds_rdma_cm_event_handler(struct rdma_cm_id *cm_id,
                break;
 
        case RDMA_CM_EVENT_DISCONNECTED:
-               printk(KERN_WARNING "RDS/IW: DISCONNECT event - dropping connection "
+               printk(KERN_WARNING "RDS/RDMA: DISCONNECT event - dropping connection "
                        "%pI4->%pI4\n", &conn->c_laddr,
                         &conn->c_faddr);
                rds_conn_drop(conn);
@@ -132,7 +132,7 @@ static int __init rds_rdma_listen_init(void)
        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, "
+               printk(KERN_ERR "RDS/RDMA: failed to setup listener, "
                       "rdma_create_id() returned %d\n", ret);
                goto out;
        }
@@ -147,14 +147,14 @@ static int __init rds_rdma_listen_init(void)
         */
        ret = rdma_bind_addr(cm_id, (struct sockaddr *)&sin);
        if (ret) {
-               printk(KERN_ERR "RDS/IW: failed to setup listener, "
+               printk(KERN_ERR "RDS/RDMA: 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, "
+               printk(KERN_ERR "RDS/RDMA: failed to setup listener, "
                       "rdma_listen() returned %d\n", ret);
                goto out;
        }
index f2118c5..86bc1a0 100644 (file)
@@ -409,18 +409,18 @@ int rds_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg,
        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;
-       }
+       while (1) {
+               /* If there are pending notifications, do those - and nothing else */
+               if (!list_empty(&rs->rs_notify_queue)) {
+                       ret = rds_notify_queue_get(rs, msg);
+                       break;
+               }
 
-       if (rs->rs_cong_notify) {
-               ret = rds_notify_cong(rs, msg);
-               goto out;
-       }
+               if (rs->rs_cong_notify) {
+                       ret = rds_notify_cong(rs, msg);
+                       break;
+               }
 
-       while (1) {
                if (!rds_next_incoming(rs, &inc)) {
                        if (nonblock) {
                                ret = -EAGAIN;
@@ -428,7 +428,9 @@ int rds_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg,
                        }
 
                        timeo = wait_event_interruptible_timeout(*sk->sk_sleep,
-                                               rds_next_incoming(rs, &inc),
+                                               (!list_empty(&rs->rs_notify_queue)
+                                               || rs->rs_cong_notify
+                                               || rds_next_incoming(rs, &inc)),
                                                timeo);
                        rdsdebug("recvmsg woke inc %p timeo %ld\n", inc,
                                 timeo);
index 2fc4a17..044de1c 100644 (file)
@@ -1091,10 +1091,16 @@ static ssize_t rfkill_fop_write(struct file *file, const char __user *buf,
        struct rfkill_event ev;
 
        /* we don't need the 'hard' variable but accept it */
-       if (count < sizeof(ev) - 1)
+       if (count < RFKILL_EVENT_SIZE_V1 - 1)
                return -EINVAL;
 
-       if (copy_from_user(&ev, buf, sizeof(ev) - 1))
+       /*
+        * Copy as much data as we can accept into our 'ev' buffer,
+        * but tell userspace how much we've copied so it can determine
+        * our API version even in a write() call, if it cares.
+        */
+       count = min(count, sizeof(ev));
+       if (copy_from_user(&ev, buf, count))
                return -EFAULT;
 
        if (ev.op != RFKILL_OP_CHANGE && ev.op != RFKILL_OP_CHANGE_ALL)
index 389d6e0..c711e2e 100644 (file)
@@ -141,7 +141,7 @@ static int rose_xmit(struct sk_buff *skb, struct net_device *dev)
        }
        dev_kfree_skb(skb);
        stats->tx_errors++;
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 static const struct header_ops rose_header_ops = {
index 9c002b6..12434b6 100644 (file)
@@ -314,7 +314,7 @@ restart:
                                        netif_wake_queue(dev);
                                        txq->tx_packets++;
                                        txq->tx_bytes += length;
-                                       return 0;
+                                       return NETDEV_TX_OK;
                                }
                                __netif_tx_unlock(slave_txq);
                        }
@@ -323,7 +323,7 @@ restart:
                        break;
                case 1:
                        master->slaves = NEXT_SLAVE(q);
-                       return 0;
+                       return NETDEV_TX_OK;
                default:
                        nores = 1;
                        break;
@@ -345,7 +345,7 @@ restart:
 drop:
        txq->tx_dropped++;
        dev_kfree_skb(skb);
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 static int teql_master_open(struct net_device *dev)
index 3c57005..7bda8e3 100644 (file)
@@ -62,7 +62,7 @@ static int handle_cmd(struct sk_buff *skb, struct genl_info *info)
                rep_nlh = nlmsg_hdr(rep_buf);
                memcpy(rep_nlh, req_nlh, hdr_space);
                rep_nlh->nlmsg_len = rep_buf->len;
-               genlmsg_unicast(rep_buf, NETLINK_CB(skb).pid);
+               genlmsg_unicast(&init_net, rep_buf, NETLINK_CB(skb).pid);
        }
 
        return 0;
index 1848693..e8254e8 100644 (file)
@@ -1748,6 +1748,12 @@ static int getsockopt(struct socket *sock,
                value = jiffies_to_msecs(sk->sk_rcvtimeo);
                /* no need to set "res", since already 0 at this point */
                break;
+        case TIPC_NODE_RECVQ_DEPTH:
+               value = (u32)atomic_read(&tipc_queue_size);
+               break;
+        case TIPC_SOCK_RECVQ_DEPTH:
+               value = skb_queue_len(&sk->sk_receive_queue);
+               break;
        default:
                res = -EINVAL;
        }
index 4428dd5..c6031d5 100644 (file)
@@ -2,6 +2,21 @@ config CFG80211
        tristate "Improved wireless configuration API"
        depends on RFKILL || !RFKILL
 
+config NL80211_TESTMODE
+       bool "nl80211 testmode command"
+       depends on CFG80211
+       help
+         The nl80211 testmode command helps implementing things like
+         factory calibration or validation tools for wireless chips.
+
+         Select this option ONLY for kernels that are specifically
+         built for such purposes.
+
+         Debugging tools that are supposed to end up in the hands of
+         users should better be implemented with debugfs.
+
+         Say N.
+
 config CFG80211_REG_DEBUG
        bool "cfg80211 regulatory debugging"
        depends on CFG80211
@@ -11,6 +26,22 @@ config CFG80211_REG_DEBUG
 
          If unsure, say N.
 
+config CFG80211_DEFAULT_PS
+       bool "enable powersave by default"
+       depends on CFG80211
+       default y
+       help
+         This option enables powersave mode by default.
+
+         If this causes your applications to misbehave you should fix your
+         applications instead -- they need to register their network
+         latency requirement, see Documentation/power/pm_qos_interface.txt.
+
+config CFG80211_DEFAULT_PS_VALUE
+       int
+       default 1 if CFG80211_DEFAULT_PS
+       default 0
+
 config CFG80211_DEBUGFS
        bool "cfg80211 DebugFS entries"
        depends on CFG80211 && DEBUG_FS
@@ -35,19 +66,13 @@ config WIRELESS_OLD_REGULATORY
 
 config WIRELESS_EXT
        bool "Wireless extensions"
-       default n
+       default y
        ---help---
          This option enables the legacy wireless extensions
          (wireless network interface configuration via ioctls.)
 
-         Wireless extensions will be replaced by cfg80211 and
-         will be required only by legacy drivers that implement
-         wireless extension handlers. This option does not
-         affect the wireless-extension backward compatibility
-         code in cfg80211.
-
-         Say N (if you can) unless you know you need wireless
-         extensions for external modules.
+         Say Y unless you've upgraded all your userspace to use
+         nl80211 instead of wireless extensions.
 
 config WIRELESS_EXT_SYSFS
        bool "Wireless extensions sysfs files"
index f78c483..d74cc77 100644 (file)
@@ -5,8 +5,8 @@ obj-$(CONFIG_LIB80211_CRYPT_WEP) += lib80211_crypt_wep.o
 obj-$(CONFIG_LIB80211_CRYPT_CCMP) += lib80211_crypt_ccmp.o
 obj-$(CONFIG_LIB80211_CRYPT_TKIP) += lib80211_crypt_tkip.o
 
-cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o mlme.o ibss.o
+cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o mlme.o ibss.o sme.o
 cfg80211-$(CONFIG_CFG80211_DEBUGFS) += debugfs.o
-cfg80211-$(CONFIG_WIRELESS_EXT) += wext-compat.o
+cfg80211-$(CONFIG_WIRELESS_EXT) += wext-compat.o wext-sme.o
 
 ccflags-y += -D__CHECK_ENDIAN__
index d585029..1a78b3c 100644 (file)
@@ -30,10 +30,10 @@ MODULE_DESCRIPTION("wireless configuration support");
 /* RCU might be appropriate here since we usually
  * only read the list, and that can happen quite
  * often because we need to do it for each command */
-LIST_HEAD(cfg80211_drv_list);
+LIST_HEAD(cfg80211_rdev_list);
 
 /*
- * This is used to protect the cfg80211_drv_list, cfg80211_regdomain,
+ * This is used to protect the cfg80211_rdev_list, cfg80211_regdomain,
  * country_ie_regdomain, the reg_beacon_list and the the last regulatory
  * request receipt (last_request).
  */
@@ -43,18 +43,18 @@ DEFINE_MUTEX(cfg80211_mutex);
 static struct dentry *ieee80211_debugfs_dir;
 
 /* requires cfg80211_mutex to be held! */
-struct cfg80211_registered_device *cfg80211_drv_by_wiphy_idx(int wiphy_idx)
+struct cfg80211_registered_device *cfg80211_rdev_by_wiphy_idx(int wiphy_idx)
 {
-       struct cfg80211_registered_device *result = NULL, *drv;
+       struct cfg80211_registered_device *result = NULL, *rdev;
 
        if (!wiphy_idx_valid(wiphy_idx))
                return NULL;
 
        assert_cfg80211_lock();
 
-       list_for_each_entry(drv, &cfg80211_drv_list, list) {
-               if (drv->wiphy_idx == wiphy_idx) {
-                       result = drv;
+       list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
+               if (rdev->wiphy_idx == wiphy_idx) {
+                       result = rdev;
                        break;
                }
        }
@@ -64,32 +64,32 @@ struct cfg80211_registered_device *cfg80211_drv_by_wiphy_idx(int wiphy_idx)
 
 int get_wiphy_idx(struct wiphy *wiphy)
 {
-       struct cfg80211_registered_device *drv;
+       struct cfg80211_registered_device *rdev;
        if (!wiphy)
                return WIPHY_IDX_STALE;
-       drv = wiphy_to_dev(wiphy);
-       return drv->wiphy_idx;
+       rdev = wiphy_to_dev(wiphy);
+       return rdev->wiphy_idx;
 }
 
-/* requires cfg80211_drv_mutex to be held! */
+/* requires cfg80211_rdev_mutex to be held! */
 struct wiphy *wiphy_idx_to_wiphy(int wiphy_idx)
 {
-       struct cfg80211_registered_device *drv;
+       struct cfg80211_registered_device *rdev;
 
        if (!wiphy_idx_valid(wiphy_idx))
                return NULL;
 
        assert_cfg80211_lock();
 
-       drv = cfg80211_drv_by_wiphy_idx(wiphy_idx);
-       if (!drv)
+       rdev = cfg80211_rdev_by_wiphy_idx(wiphy_idx);
+       if (!rdev)
                return NULL;
-       return &drv->wiphy;
+       return &rdev->wiphy;
 }
 
 /* requires cfg80211_mutex to be held! */
 struct cfg80211_registered_device *
-__cfg80211_drv_from_info(struct genl_info *info)
+__cfg80211_rdev_from_info(struct genl_info *info)
 {
        int ifindex;
        struct cfg80211_registered_device *bywiphyidx = NULL, *byifidx = NULL;
@@ -99,7 +99,7 @@ __cfg80211_drv_from_info(struct genl_info *info)
        assert_cfg80211_lock();
 
        if (info->attrs[NL80211_ATTR_WIPHY]) {
-               bywiphyidx = cfg80211_drv_by_wiphy_idx(
+               bywiphyidx = cfg80211_rdev_by_wiphy_idx(
                                nla_get_u32(info->attrs[NL80211_ATTR_WIPHY]));
                err = -ENODEV;
        }
@@ -134,26 +134,26 @@ __cfg80211_drv_from_info(struct genl_info *info)
 struct cfg80211_registered_device *
 cfg80211_get_dev_from_info(struct genl_info *info)
 {
-       struct cfg80211_registered_device *drv;
+       struct cfg80211_registered_device *rdev;
 
        mutex_lock(&cfg80211_mutex);
-       drv = __cfg80211_drv_from_info(info);
+       rdev = __cfg80211_rdev_from_info(info);
 
        /* if it is not an error we grab the lock on
         * it to assure it won't be going away while
         * we operate on it */
-       if (!IS_ERR(drv))
-               mutex_lock(&drv->mtx);
+       if (!IS_ERR(rdev))
+               mutex_lock(&rdev->mtx);
 
        mutex_unlock(&cfg80211_mutex);
 
-       return drv;
+       return rdev;
 }
 
 struct cfg80211_registered_device *
 cfg80211_get_dev_from_ifindex(int ifindex)
 {
-       struct cfg80211_registered_device *drv = ERR_PTR(-ENODEV);
+       struct cfg80211_registered_device *rdev = ERR_PTR(-ENODEV);
        struct net_device *dev;
 
        mutex_lock(&cfg80211_mutex);
@@ -161,27 +161,21 @@ cfg80211_get_dev_from_ifindex(int ifindex)
        if (!dev)
                goto out;
        if (dev->ieee80211_ptr) {
-               drv = wiphy_to_dev(dev->ieee80211_ptr->wiphy);
-               mutex_lock(&drv->mtx);
+               rdev = wiphy_to_dev(dev->ieee80211_ptr->wiphy);
+               mutex_lock(&rdev->mtx);
        } else
-               drv = ERR_PTR(-ENODEV);
+               rdev = ERR_PTR(-ENODEV);
        dev_put(dev);
  out:
        mutex_unlock(&cfg80211_mutex);
-       return drv;
-}
-
-void cfg80211_put_dev(struct cfg80211_registered_device *drv)
-{
-       BUG_ON(IS_ERR(drv));
-       mutex_unlock(&drv->mtx);
+       return rdev;
 }
 
 /* requires cfg80211_mutex to be held */
 int cfg80211_dev_rename(struct cfg80211_registered_device *rdev,
                        char *newname)
 {
-       struct cfg80211_registered_device *drv;
+       struct cfg80211_registered_device *rdev2;
        int wiphy_idx, taken = -1, result, digits;
 
        assert_cfg80211_lock();
@@ -207,8 +201,8 @@ int cfg80211_dev_rename(struct cfg80211_registered_device *rdev,
                return 0;
 
        /* Ensure another device does not already have this name. */
-       list_for_each_entry(drv, &cfg80211_drv_list, list)
-               if (strcmp(newname, dev_name(&drv->wiphy.dev)) == 0)
+       list_for_each_entry(rdev2, &cfg80211_rdev_list, list)
+               if (strcmp(newname, dev_name(&rdev2->wiphy.dev)) == 0)
                        return -EINVAL;
 
        result = device_rename(&rdev->wiphy.dev, newname);
@@ -230,26 +224,26 @@ int cfg80211_dev_rename(struct cfg80211_registered_device *rdev,
 
 static void cfg80211_rfkill_poll(struct rfkill *rfkill, void *data)
 {
-       struct cfg80211_registered_device *drv = data;
+       struct cfg80211_registered_device *rdev = data;
 
-       drv->ops->rfkill_poll(&drv->wiphy);
+       rdev->ops->rfkill_poll(&rdev->wiphy);
 }
 
 static int cfg80211_rfkill_set_block(void *data, bool blocked)
 {
-       struct cfg80211_registered_device *drv = data;
+       struct cfg80211_registered_device *rdev = data;
        struct wireless_dev *wdev;
 
        if (!blocked)
                return 0;
 
        rtnl_lock();
-       mutex_lock(&drv->devlist_mtx);
+       mutex_lock(&rdev->devlist_mtx);
 
-       list_for_each_entry(wdev, &drv->netdev_list, list)
+       list_for_each_entry(wdev, &rdev->netdev_list, list)
                dev_close(wdev->netdev);
 
-       mutex_unlock(&drv->devlist_mtx);
+       mutex_unlock(&rdev->devlist_mtx);
        rtnl_unlock();
 
        return 0;
@@ -257,10 +251,75 @@ static int cfg80211_rfkill_set_block(void *data, bool blocked)
 
 static void cfg80211_rfkill_sync_work(struct work_struct *work)
 {
-       struct cfg80211_registered_device *drv;
+       struct cfg80211_registered_device *rdev;
+
+       rdev = container_of(work, struct cfg80211_registered_device, rfkill_sync);
+       cfg80211_rfkill_set_block(rdev, rfkill_blocked(rdev->rfkill));
+}
+
+static void cfg80211_process_events(struct wireless_dev *wdev)
+{
+       struct cfg80211_event *ev;
+       unsigned long flags;
+
+       spin_lock_irqsave(&wdev->event_lock, flags);
+       while (!list_empty(&wdev->event_list)) {
+               ev = list_first_entry(&wdev->event_list,
+                                     struct cfg80211_event, list);
+               list_del(&ev->list);
+               spin_unlock_irqrestore(&wdev->event_lock, flags);
+
+               wdev_lock(wdev);
+               switch (ev->type) {
+               case EVENT_CONNECT_RESULT:
+                       __cfg80211_connect_result(
+                               wdev->netdev, ev->cr.bssid,
+                               ev->cr.req_ie, ev->cr.req_ie_len,
+                               ev->cr.resp_ie, ev->cr.resp_ie_len,
+                               ev->cr.status,
+                               ev->cr.status == WLAN_STATUS_SUCCESS);
+                       break;
+               case EVENT_ROAMED:
+                       __cfg80211_roamed(wdev, ev->rm.bssid,
+                                         ev->rm.req_ie, ev->rm.req_ie_len,
+                                         ev->rm.resp_ie, ev->rm.resp_ie_len);
+                       break;
+               case EVENT_DISCONNECTED:
+                       __cfg80211_disconnected(wdev->netdev,
+                                               ev->dc.ie, ev->dc.ie_len,
+                                               ev->dc.reason, true);
+                       break;
+               case EVENT_IBSS_JOINED:
+                       __cfg80211_ibss_joined(wdev->netdev, ev->ij.bssid);
+                       break;
+               }
+               wdev_unlock(wdev);
+
+               kfree(ev);
 
-       drv = container_of(work, struct cfg80211_registered_device, rfkill_sync);
-       cfg80211_rfkill_set_block(drv, rfkill_blocked(drv->rfkill));
+               spin_lock_irqsave(&wdev->event_lock, flags);
+       }
+       spin_unlock_irqrestore(&wdev->event_lock, flags);
+}
+
+static void cfg80211_event_work(struct work_struct *work)
+{
+       struct cfg80211_registered_device *rdev;
+       struct wireless_dev *wdev;
+
+       rdev = container_of(work, struct cfg80211_registered_device,
+                           event_work);
+
+       rtnl_lock();
+       cfg80211_lock_rdev(rdev);
+       mutex_lock(&rdev->devlist_mtx);
+
+       list_for_each_entry(wdev, &rdev->netdev_list, list)
+               cfg80211_process_events(wdev);
+
+       mutex_unlock(&rdev->devlist_mtx);
+       cfg80211_unlock_rdev(rdev);
+       rtnl_unlock();
 }
 
 /* exported functions */
@@ -269,76 +328,84 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv)
 {
        static int wiphy_counter;
 
-       struct cfg80211_registered_device *drv;
+       struct cfg80211_registered_device *rdev;
        int alloc_size;
 
-       WARN_ON(!ops->add_key && ops->del_key);
-       WARN_ON(ops->add_key && !ops->del_key);
+       WARN_ON(ops->add_key && (!ops->del_key || !ops->set_default_key));
+       WARN_ON(ops->auth && (!ops->assoc || !ops->deauth || !ops->disassoc));
+       WARN_ON(ops->connect && !ops->disconnect);
+       WARN_ON(ops->join_ibss && !ops->leave_ibss);
+       WARN_ON(ops->add_virtual_intf && !ops->del_virtual_intf);
+       WARN_ON(ops->add_station && !ops->del_station);
+       WARN_ON(ops->add_mpath && !ops->del_mpath);
 
-       alloc_size = sizeof(*drv) + sizeof_priv;
+       alloc_size = sizeof(*rdev) + sizeof_priv;
 
-       drv = kzalloc(alloc_size, GFP_KERNEL);
-       if (!drv)
+       rdev = kzalloc(alloc_size, GFP_KERNEL);
+       if (!rdev)
                return NULL;
 
-       drv->ops = ops;
+       rdev->ops = ops;
 
        mutex_lock(&cfg80211_mutex);
 
-       drv->wiphy_idx = wiphy_counter++;
+       rdev->wiphy_idx = wiphy_counter++;
 
-       if (unlikely(!wiphy_idx_valid(drv->wiphy_idx))) {
+       if (unlikely(!wiphy_idx_valid(rdev->wiphy_idx))) {
                wiphy_counter--;
                mutex_unlock(&cfg80211_mutex);
                /* ugh, wrapped! */
-               kfree(drv);
+               kfree(rdev);
                return NULL;
        }
 
        mutex_unlock(&cfg80211_mutex);
 
        /* give it a proper name */
-       dev_set_name(&drv->wiphy.dev, PHY_NAME "%d", drv->wiphy_idx);
-
-       mutex_init(&drv->mtx);
-       mutex_init(&drv->devlist_mtx);
-       INIT_LIST_HEAD(&drv->netdev_list);
-       spin_lock_init(&drv->bss_lock);
-       INIT_LIST_HEAD(&drv->bss_list);
-
-       device_initialize(&drv->wiphy.dev);
-       drv->wiphy.dev.class = &ieee80211_class;
-       drv->wiphy.dev.platform_data = drv;
-
-       drv->rfkill_ops.set_block = cfg80211_rfkill_set_block;
-       drv->rfkill = rfkill_alloc(dev_name(&drv->wiphy.dev),
-                                  &drv->wiphy.dev, RFKILL_TYPE_WLAN,
-                                  &drv->rfkill_ops, drv);
-
-       if (!drv->rfkill) {
-               kfree(drv);
+       dev_set_name(&rdev->wiphy.dev, PHY_NAME "%d", rdev->wiphy_idx);
+
+       mutex_init(&rdev->mtx);
+       mutex_init(&rdev->devlist_mtx);
+       INIT_LIST_HEAD(&rdev->netdev_list);
+       spin_lock_init(&rdev->bss_lock);
+       INIT_LIST_HEAD(&rdev->bss_list);
+       INIT_WORK(&rdev->scan_done_wk, __cfg80211_scan_done);
+
+       device_initialize(&rdev->wiphy.dev);
+       rdev->wiphy.dev.class = &ieee80211_class;
+       rdev->wiphy.dev.platform_data = rdev;
+
+       rdev->rfkill_ops.set_block = cfg80211_rfkill_set_block;
+       rdev->rfkill = rfkill_alloc(dev_name(&rdev->wiphy.dev),
+                                  &rdev->wiphy.dev, RFKILL_TYPE_WLAN,
+                                  &rdev->rfkill_ops, rdev);
+
+       if (!rdev->rfkill) {
+               kfree(rdev);
                return NULL;
        }
 
-       INIT_WORK(&drv->rfkill_sync, cfg80211_rfkill_sync_work);
+       INIT_WORK(&rdev->rfkill_sync, cfg80211_rfkill_sync_work);
+       INIT_WORK(&rdev->conn_work, cfg80211_conn_work);
+       INIT_WORK(&rdev->event_work, cfg80211_event_work);
 
        /*
         * Initialize wiphy parameters to IEEE 802.11 MIB default values.
         * Fragmentation and RTS threshold are disabled by default with the
         * special -1 value.
         */
-       drv->wiphy.retry_short = 7;
-       drv->wiphy.retry_long = 4;
-       drv->wiphy.frag_threshold = (u32) -1;
-       drv->wiphy.rts_threshold = (u32) -1;
+       rdev->wiphy.retry_short = 7;
+       rdev->wiphy.retry_long = 4;
+       rdev->wiphy.frag_threshold = (u32) -1;
+       rdev->wiphy.rts_threshold = (u32) -1;
 
-       return &drv->wiphy;
+       return &rdev->wiphy;
 }
 EXPORT_SYMBOL(wiphy_new);
 
 int wiphy_register(struct wiphy *wiphy)
 {
-       struct cfg80211_registered_device *drv = wiphy_to_dev(wiphy);
+       struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
        int res;
        enum ieee80211_band band;
        struct ieee80211_supported_band *sband;
@@ -346,9 +413,6 @@ int wiphy_register(struct wiphy *wiphy)
        int i;
        u16 ifmodes = wiphy->interface_modes;
 
-       if (WARN_ON(wiphy->max_scan_ssids < 1))
-               return -EINVAL;
-
        /* sanity check ifmodes */
        WARN_ON(!ifmodes);
        ifmodes &= ((1 << __NL80211_IFTYPE_AFTER_LAST) - 1) & ~1;
@@ -395,11 +459,11 @@ int wiphy_register(struct wiphy *wiphy)
        /* check and set up bitrates */
        ieee80211_set_bitrate_flags(wiphy);
 
-       res = device_add(&drv->wiphy.dev);
+       res = device_add(&rdev->wiphy.dev);
        if (res)
                return res;
 
-       res = rfkill_register(drv->rfkill);
+       res = rfkill_register(rdev->rfkill);
        if (res)
                goto out_rm_dev;
 
@@ -408,16 +472,16 @@ int wiphy_register(struct wiphy *wiphy)
        /* set up regulatory info */
        wiphy_update_regulatory(wiphy, NL80211_REGDOM_SET_BY_CORE);
 
-       list_add(&drv->list, &cfg80211_drv_list);
+       list_add(&rdev->list, &cfg80211_rdev_list);
 
        mutex_unlock(&cfg80211_mutex);
 
        /* add to debugfs */
-       drv->wiphy.debugfsdir =
-               debugfs_create_dir(wiphy_name(&drv->wiphy),
+       rdev->wiphy.debugfsdir =
+               debugfs_create_dir(wiphy_name(&rdev->wiphy),
                                   ieee80211_debugfs_dir);
-       if (IS_ERR(drv->wiphy.debugfsdir))
-               drv->wiphy.debugfsdir = NULL;
+       if (IS_ERR(rdev->wiphy.debugfsdir))
+               rdev->wiphy.debugfsdir = NULL;
 
        if (wiphy->custom_regulatory) {
                struct regulatory_request request;
@@ -430,48 +494,48 @@ int wiphy_register(struct wiphy *wiphy)
                nl80211_send_reg_change_event(&request);
        }
 
-       cfg80211_debugfs_drv_add(drv);
+       cfg80211_debugfs_rdev_add(rdev);
 
        return 0;
 
  out_rm_dev:
-       device_del(&drv->wiphy.dev);
+       device_del(&rdev->wiphy.dev);
        return res;
 }
 EXPORT_SYMBOL(wiphy_register);
 
 void wiphy_rfkill_start_polling(struct wiphy *wiphy)
 {
-       struct cfg80211_registered_device *drv = wiphy_to_dev(wiphy);
+       struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
 
-       if (!drv->ops->rfkill_poll)
+       if (!rdev->ops->rfkill_poll)
                return;
-       drv->rfkill_ops.poll = cfg80211_rfkill_poll;
-       rfkill_resume_polling(drv->rfkill);
+       rdev->rfkill_ops.poll = cfg80211_rfkill_poll;
+       rfkill_resume_polling(rdev->rfkill);
 }
 EXPORT_SYMBOL(wiphy_rfkill_start_polling);
 
 void wiphy_rfkill_stop_polling(struct wiphy *wiphy)
 {
-       struct cfg80211_registered_device *drv = wiphy_to_dev(wiphy);
+       struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
 
-       rfkill_pause_polling(drv->rfkill);
+       rfkill_pause_polling(rdev->rfkill);
 }
 EXPORT_SYMBOL(wiphy_rfkill_stop_polling);
 
 void wiphy_unregister(struct wiphy *wiphy)
 {
-       struct cfg80211_registered_device *drv = wiphy_to_dev(wiphy);
+       struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
 
-       rfkill_unregister(drv->rfkill);
+       rfkill_unregister(rdev->rfkill);
 
        /* protect the device list */
        mutex_lock(&cfg80211_mutex);
 
-       BUG_ON(!list_empty(&drv->netdev_list));
+       BUG_ON(!list_empty(&rdev->netdev_list));
 
        /*
-        * Try to grab drv->mtx. If a command is still in progress,
+        * Try to grab rdev->mtx. If a command is still in progress,
         * hopefully the driver will refuse it since it's tearing
         * down the device already. We wait for this command to complete
         * before unlinking the item from the list.
@@ -480,33 +544,38 @@ void wiphy_unregister(struct wiphy *wiphy)
         * get to lock contention here if userspace issues a command
         * that identified the hardware by wiphy index.
         */
-       mutex_lock(&drv->mtx);
+       mutex_lock(&rdev->mtx);
        /* unlock again before freeing */
-       mutex_unlock(&drv->mtx);
+       mutex_unlock(&rdev->mtx);
 
-       cfg80211_debugfs_drv_del(drv);
+       cancel_work_sync(&rdev->conn_work);
+       cancel_work_sync(&rdev->scan_done_wk);
+       kfree(rdev->scan_req);
+       flush_work(&rdev->event_work);
+
+       cfg80211_debugfs_rdev_del(rdev);
 
        /* If this device got a regulatory hint tell core its
         * free to listen now to a new shiny device regulatory hint */
        reg_device_remove(wiphy);
 
-       list_del(&drv->list);
-       device_del(&drv->wiphy.dev);
-       debugfs_remove(drv->wiphy.debugfsdir);
+       list_del(&rdev->list);
+       device_del(&rdev->wiphy.dev);
+       debugfs_remove(rdev->wiphy.debugfsdir);
 
        mutex_unlock(&cfg80211_mutex);
 }
 EXPORT_SYMBOL(wiphy_unregister);
 
-void cfg80211_dev_free(struct cfg80211_registered_device *drv)
+void cfg80211_dev_free(struct cfg80211_registered_device *rdev)
 {
        struct cfg80211_internal_bss *scan, *tmp;
-       rfkill_destroy(drv->rfkill);
-       mutex_destroy(&drv->mtx);
-       mutex_destroy(&drv->devlist_mtx);
-       list_for_each_entry_safe(scan, tmp, &drv->bss_list, list)
+       rfkill_destroy(rdev->rfkill);
+       mutex_destroy(&rdev->mtx);
+       mutex_destroy(&rdev->devlist_mtx);
+       list_for_each_entry_safe(scan, tmp, &rdev->bss_list, list)
                cfg80211_put_bss(&scan->pub);
-       kfree(drv);
+       kfree(rdev);
 }
 
 void wiphy_free(struct wiphy *wiphy)
@@ -517,10 +586,10 @@ EXPORT_SYMBOL(wiphy_free);
 
 void wiphy_rfkill_set_hw_state(struct wiphy *wiphy, bool blocked)
 {
-       struct cfg80211_registered_device *drv = wiphy_to_dev(wiphy);
+       struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
 
-       if (rfkill_set_hw_state(drv->rfkill, blocked))
-               schedule_work(&drv->rfkill_sync);
+       if (rfkill_set_hw_state(rdev->rfkill, blocked))
+               schedule_work(&rdev->rfkill_sync);
 }
 EXPORT_SYMBOL(wiphy_rfkill_set_hw_state);
 
@@ -529,56 +598,102 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
                                         void *ndev)
 {
        struct net_device *dev = ndev;
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
        struct cfg80211_registered_device *rdev;
 
-       if (!dev->ieee80211_ptr)
+       if (!wdev)
                return NOTIFY_DONE;
 
-       rdev = wiphy_to_dev(dev->ieee80211_ptr->wiphy);
+       rdev = wiphy_to_dev(wdev->wiphy);
 
-       WARN_ON(dev->ieee80211_ptr->iftype == NL80211_IFTYPE_UNSPECIFIED);
+       WARN_ON(wdev->iftype == NL80211_IFTYPE_UNSPECIFIED);
 
        switch (state) {
        case NETDEV_REGISTER:
+               mutex_init(&wdev->mtx);
+               INIT_LIST_HEAD(&wdev->event_list);
+               spin_lock_init(&wdev->event_lock);
                mutex_lock(&rdev->devlist_mtx);
-               list_add(&dev->ieee80211_ptr->list, &rdev->netdev_list);
+               list_add(&wdev->list, &rdev->netdev_list);
                if (sysfs_create_link(&dev->dev.kobj, &rdev->wiphy.dev.kobj,
                                      "phy80211")) {
                        printk(KERN_ERR "wireless: failed to add phy80211 "
                                "symlink to netdev!\n");
                }
-               dev->ieee80211_ptr->netdev = dev;
+               wdev->netdev = dev;
+               wdev->sme_state = CFG80211_SME_IDLE;
+               mutex_unlock(&rdev->devlist_mtx);
 #ifdef CONFIG_WIRELESS_EXT
-               dev->ieee80211_ptr->wext.default_key = -1;
-               dev->ieee80211_ptr->wext.default_mgmt_key = -1;
+               wdev->wext.default_key = -1;
+               wdev->wext.default_mgmt_key = -1;
+               wdev->wext.connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC;
+               wdev->wext.ps = CONFIG_CFG80211_DEFAULT_PS_VALUE;
+               wdev->wext.ps_timeout = 500;
+               if (rdev->ops->set_power_mgmt)
+                       if (rdev->ops->set_power_mgmt(wdev->wiphy, dev,
+                                                     wdev->wext.ps,
+                                                     wdev->wext.ps_timeout)) {
+                               /* assume this means it's off */
+                               wdev->wext.ps = false;
+                       }
 #endif
-               mutex_unlock(&rdev->devlist_mtx);
                break;
        case NETDEV_GOING_DOWN:
-               if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC)
+               switch (wdev->iftype) {
+               case NL80211_IFTYPE_ADHOC:
+                       cfg80211_leave_ibss(rdev, dev, true);
+                       break;
+               case NL80211_IFTYPE_STATION:
+                       wdev_lock(wdev);
+#ifdef CONFIG_WIRELESS_EXT
+                       kfree(wdev->wext.ie);
+                       wdev->wext.ie = NULL;
+                       wdev->wext.ie_len = 0;
+                       wdev->wext.connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC;
+#endif
+                       __cfg80211_disconnect(rdev, dev,
+                                             WLAN_REASON_DEAUTH_LEAVING, true);
+                       cfg80211_mlme_down(rdev, dev);
+                       wdev_unlock(wdev);
                        break;
-               if (!dev->ieee80211_ptr->ssid_len)
+               default:
                        break;
-               cfg80211_leave_ibss(rdev, dev, true);
+               }
                break;
        case NETDEV_UP:
 #ifdef CONFIG_WIRELESS_EXT
-               if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC)
+               cfg80211_lock_rdev(rdev);
+               wdev_lock(wdev);
+               switch (wdev->iftype) {
+               case NL80211_IFTYPE_ADHOC:
+                       if (wdev->wext.ibss.ssid_len)
+                               __cfg80211_join_ibss(rdev, dev,
+                                                    &wdev->wext.ibss);
                        break;
-               if (!dev->ieee80211_ptr->wext.ibss.ssid_len)
+               case NL80211_IFTYPE_STATION:
+                       if (wdev->wext.connect.ssid_len)
+                               __cfg80211_connect(rdev, dev,
+                                                  &wdev->wext.connect);
                        break;
-               cfg80211_join_ibss(rdev, dev, &dev->ieee80211_ptr->wext.ibss);
-               break;
+               default:
+                       break;
+               }
+               wdev_unlock(wdev);
+               cfg80211_unlock_rdev(rdev);
 #endif
+               break;
        case NETDEV_UNREGISTER:
                mutex_lock(&rdev->devlist_mtx);
-               if (!list_empty(&dev->ieee80211_ptr->list)) {
+               if (!list_empty(&wdev->list)) {
                        sysfs_remove_link(&dev->dev.kobj, "phy80211");
-                       list_del_init(&dev->ieee80211_ptr->list);
+                       list_del_init(&wdev->list);
                }
                mutex_unlock(&rdev->devlist_mtx);
+               mutex_destroy(&wdev->mtx);
                break;
        case NETDEV_PRE_UP:
+               if (!(wdev->wiphy->interface_modes & BIT(wdev->iftype)))
+                       return notifier_from_errno(-EOPNOTSUPP);
                if (rfkill_blocked(rdev->rfkill))
                        return notifier_from_errno(-ERFKILL);
                break;
index bfa340c..e46cd6e 100644 (file)
@@ -57,6 +57,14 @@ struct cfg80211_registered_device {
        u32 bss_generation;
        struct cfg80211_scan_request *scan_req; /* protected by RTNL */
        unsigned long suspend_at;
+       struct work_struct scan_done_wk;
+
+#ifdef CONFIG_NL80211_TESTMODE
+       struct genl_info *testmode_info;
+#endif
+
+       struct work_struct conn_work;
+       struct work_struct event_work;
 
 #ifdef CONFIG_CFG80211_DEBUGFS
        /* Debugfs entries */
@@ -89,13 +97,13 @@ bool wiphy_idx_valid(int wiphy_idx)
 }
 
 extern struct mutex cfg80211_mutex;
-extern struct list_head cfg80211_drv_list;
+extern struct list_head cfg80211_rdev_list;
 
 #define assert_cfg80211_lock() 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
+ * It guarantees cfg80211_rdev_by_wiphy_idx(wiphy_idx) will return NULL
  */
 #define WIPHY_IDX_STALE -1
 
@@ -104,17 +112,35 @@ struct cfg80211_internal_bss {
        struct rb_node rbn;
        unsigned long ts;
        struct kref ref;
-       bool hold, ies_allocated;
+       atomic_t hold;
+       bool ies_allocated;
 
        /* must be last because of priv member */
        struct cfg80211_bss pub;
 };
 
-struct cfg80211_registered_device *cfg80211_drv_by_wiphy_idx(int wiphy_idx);
+static inline struct cfg80211_internal_bss *bss_from_pub(struct cfg80211_bss *pub)
+{
+       return container_of(pub, struct cfg80211_internal_bss, pub);
+}
+
+static inline void cfg80211_hold_bss(struct cfg80211_internal_bss *bss)
+{
+       atomic_inc(&bss->hold);
+}
+
+static inline void cfg80211_unhold_bss(struct cfg80211_internal_bss *bss)
+{
+       int r = atomic_dec_return(&bss->hold);
+       WARN_ON(r < 0);
+}
+
+
+struct cfg80211_registered_device *cfg80211_rdev_by_wiphy_idx(int wiphy_idx);
 int get_wiphy_idx(struct wiphy *wiphy);
 
 struct cfg80211_registered_device *
-__cfg80211_drv_from_info(struct genl_info *info);
+__cfg80211_rdev_from_info(struct genl_info *info);
 
 /*
  * This function returns a pointer to the driver
@@ -122,12 +148,12 @@ __cfg80211_drv_from_info(struct genl_info *info);
  * If successful, it returns non-NULL and also locks
  * the driver's mutex!
  *
- * This means that you need to call cfg80211_put_dev()
+ * This means that you need to call cfg80211_unlock_rdev()
  * 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 lock the rdev mutex so it doesn't go away under us.
  *
  * We don't want to keep cfg80211_mutex locked
  * for all the time in order to allow requests on
@@ -139,19 +165,84 @@ __cfg80211_drv_from_info(struct genl_info *info);
 extern struct cfg80211_registered_device *
 cfg80211_get_dev_from_info(struct genl_info *info);
 
-/* requires cfg80211_drv_mutex to be held! */
+/* requires cfg80211_rdev_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);
 
-extern void cfg80211_put_dev(struct cfg80211_registered_device *drv);
+static inline void cfg80211_lock_rdev(struct cfg80211_registered_device *rdev)
+{
+       mutex_lock(&rdev->mtx);
+}
+
+static inline void cfg80211_unlock_rdev(struct cfg80211_registered_device *rdev)
+{
+       BUG_ON(IS_ERR(rdev) || !rdev);
+       mutex_unlock(&rdev->mtx);
+}
+
+static inline void wdev_lock(struct wireless_dev *wdev)
+       __acquires(wdev)
+{
+       mutex_lock(&wdev->mtx);
+       __acquire(wdev->mtx);
+}
+
+static inline void wdev_unlock(struct wireless_dev *wdev)
+       __releases(wdev)
+{
+       __release(wdev->mtx);
+       mutex_unlock(&wdev->mtx);
+}
+
+#define ASSERT_RDEV_LOCK(rdev) WARN_ON(!mutex_is_locked(&(rdev)->mtx));
+#define ASSERT_WDEV_LOCK(wdev) WARN_ON(!mutex_is_locked(&(wdev)->mtx));
+
+enum cfg80211_event_type {
+       EVENT_CONNECT_RESULT,
+       EVENT_ROAMED,
+       EVENT_DISCONNECTED,
+       EVENT_IBSS_JOINED,
+};
+
+struct cfg80211_event {
+       struct list_head list;
+       enum cfg80211_event_type type;
+
+       union {
+               struct {
+                       u8 bssid[ETH_ALEN];
+                       const u8 *req_ie;
+                       const u8 *resp_ie;
+                       size_t req_ie_len;
+                       size_t resp_ie_len;
+                       u16 status;
+               } cr;
+               struct {
+                       u8 bssid[ETH_ALEN];
+                       const u8 *req_ie;
+                       const u8 *resp_ie;
+                       size_t req_ie_len;
+                       size_t resp_ie_len;
+               } rm;
+               struct {
+                       const u8 *ie;
+                       size_t ie_len;
+                       u16 reason;
+               } dc;
+               struct {
+                       u8 bssid[ETH_ALEN];
+               } ij;
+       };
+};
+
 
 /* free object */
-extern void cfg80211_dev_free(struct cfg80211_registered_device *drv);
+extern void cfg80211_dev_free(struct cfg80211_registered_device *rdev);
 
-extern int cfg80211_dev_rename(struct cfg80211_registered_device *drv,
+extern int cfg80211_dev_rename(struct cfg80211_registered_device *rdev,
                               char *newname);
 
 void ieee80211_set_bitrate_flags(struct wiphy *wiphy);
@@ -163,15 +254,86 @@ void cfg80211_bss_age(struct cfg80211_registered_device *dev,
                       unsigned long age_secs);
 
 /* IBSS */
+int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
+                        struct net_device *dev,
+                        struct cfg80211_ibss_params *params);
 int cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
                       struct net_device *dev,
                       struct cfg80211_ibss_params *params);
 void cfg80211_clear_ibss(struct net_device *dev, bool nowext);
 int cfg80211_leave_ibss(struct cfg80211_registered_device *rdev,
                        struct net_device *dev, bool nowext);
+void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid);
+
+/* MLME */
+int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
+                        struct net_device *dev,
+                        struct ieee80211_channel *chan,
+                        enum nl80211_auth_type auth_type,
+                        const u8 *bssid,
+                        const u8 *ssid, int ssid_len,
+                        const u8 *ie, int ie_len);
+int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
+                      struct net_device *dev, struct ieee80211_channel *chan,
+                      enum nl80211_auth_type auth_type, const u8 *bssid,
+                      const u8 *ssid, int ssid_len,
+                      const u8 *ie, int ie_len);
+int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
+                         struct net_device *dev,
+                         struct ieee80211_channel *chan,
+                         const u8 *bssid, const u8 *prev_bssid,
+                         const u8 *ssid, int ssid_len,
+                         const u8 *ie, int ie_len, bool use_mfp,
+                         struct cfg80211_crypto_settings *crypt);
+int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
+                       struct net_device *dev, struct ieee80211_channel *chan,
+                       const u8 *bssid, const u8 *prev_bssid,
+                       const u8 *ssid, int ssid_len,
+                       const u8 *ie, int ie_len, bool use_mfp,
+                       struct cfg80211_crypto_settings *crypt);
+int __cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev,
+                          struct net_device *dev, const u8 *bssid,
+                          const u8 *ie, int ie_len, u16 reason);
+int cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev,
+                        struct net_device *dev, const u8 *bssid,
+                        const u8 *ie, int ie_len, u16 reason);
+int cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev,
+                          struct net_device *dev, const u8 *bssid,
+                          const u8 *ie, int ie_len, u16 reason);
+void cfg80211_mlme_down(struct cfg80211_registered_device *rdev,
+                       struct net_device *dev);
+void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
+                              const u8 *req_ie, size_t req_ie_len,
+                              const u8 *resp_ie, size_t resp_ie_len,
+                              u16 status, bool wextev);
+
+/* SME */
+int __cfg80211_connect(struct cfg80211_registered_device *rdev,
+                      struct net_device *dev,
+                      struct cfg80211_connect_params *connect);
+int cfg80211_connect(struct cfg80211_registered_device *rdev,
+                    struct net_device *dev,
+                    struct cfg80211_connect_params *connect);
+int __cfg80211_disconnect(struct cfg80211_registered_device *rdev,
+                         struct net_device *dev, u16 reason,
+                         bool wextev);
+int cfg80211_disconnect(struct cfg80211_registered_device *rdev,
+                       struct net_device *dev, u16 reason,
+                       bool wextev);
+void __cfg80211_roamed(struct wireless_dev *wdev, const u8 *bssid,
+                      const u8 *req_ie, size_t req_ie_len,
+                      const u8 *resp_ie, size_t resp_ie_len);
+
+void cfg80211_conn_work(struct work_struct *work);
 
 /* internal helpers */
 int cfg80211_validate_key_settings(struct key_params *params, int key_idx,
                                   const u8 *mac_addr);
+void __cfg80211_disconnected(struct net_device *dev, const u8 *ie,
+                            size_t ie_len, u16 reason, bool from_ap);
+void cfg80211_sme_scan_done(struct net_device *dev);
+void cfg80211_sme_rx_auth(struct net_device *dev, const u8 *buf, size_t len);
+void cfg80211_sme_disassoc(struct net_device *dev, int idx);
+void __cfg80211_scan_done(struct work_struct *wk);
 
 #endif /* __NET_WIRELESS_CORE_H */
index 679ddfc..13d93d8 100644 (file)
@@ -104,15 +104,15 @@ static const struct file_operations ht40allow_map_ops = {
 };
 
 #define DEBUGFS_ADD(name)                                              \
-       drv->debugfs.name = debugfs_create_file(#name, S_IRUGO, phyd,   \
-                                                 &drv->wiphy, &name## _ops);
+       rdev->debugfs.name = debugfs_create_file(#name, S_IRUGO, phyd,  \
+                                                 &rdev->wiphy, &name## _ops);
 #define DEBUGFS_DEL(name)                                              \
-       debugfs_remove(drv->debugfs.name);                              \
-       drv->debugfs.name = NULL;
+       debugfs_remove(rdev->debugfs.name);                             \
+       rdev->debugfs.name = NULL;
 
-void cfg80211_debugfs_drv_add(struct cfg80211_registered_device *drv)
+void cfg80211_debugfs_rdev_add(struct cfg80211_registered_device *rdev)
 {
-       struct dentry *phyd = drv->wiphy.debugfsdir;
+       struct dentry *phyd = rdev->wiphy.debugfsdir;
 
        DEBUGFS_ADD(rts_threshold);
        DEBUGFS_ADD(fragmentation_threshold);
@@ -121,7 +121,7 @@ void cfg80211_debugfs_drv_add(struct cfg80211_registered_device *drv)
        DEBUGFS_ADD(ht40allow_map);
 }
 
-void cfg80211_debugfs_drv_del(struct cfg80211_registered_device *drv)
+void cfg80211_debugfs_rdev_del(struct cfg80211_registered_device *rdev)
 {
        DEBUGFS_DEL(rts_threshold);
        DEBUGFS_DEL(fragmentation_threshold);
index c226983..6419b6d 100644 (file)
@@ -2,13 +2,13 @@
 #define __CFG80211_DEBUGFS_H
 
 #ifdef CONFIG_CFG80211_DEBUGFS
-void cfg80211_debugfs_drv_add(struct cfg80211_registered_device *drv);
-void cfg80211_debugfs_drv_del(struct cfg80211_registered_device *drv);
+void cfg80211_debugfs_rdev_add(struct cfg80211_registered_device *rdev);
+void cfg80211_debugfs_rdev_del(struct cfg80211_registered_device *rdev);
 #else
 static inline
-void cfg80211_debugfs_drv_add(struct cfg80211_registered_device *drv) {}
+void cfg80211_debugfs_rdev_add(struct cfg80211_registered_device *rdev) {}
 static inline
-void cfg80211_debugfs_drv_del(struct cfg80211_registered_device *drv) {}
+void cfg80211_debugfs_rdev_del(struct cfg80211_registered_device *rdev) {}
 #endif
 
 #endif /* __CFG80211_DEBUGFS_H */
index a4a1c34..99ef936 100644 (file)
@@ -10,7 +10,7 @@
 #include "nl80211.h"
 
 
-void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, gfp_t gfp)
+void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
        struct cfg80211_bss *bss;
@@ -24,9 +24,6 @@ void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, gfp_t gfp)
        if (WARN_ON(!wdev->ssid_len))
                return;
 
-       if (memcmp(bssid, wdev->bssid, ETH_ALEN) == 0)
-               return;
-
        bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid,
                               wdev->ssid, wdev->ssid_len,
                               WLAN_CAPABILITY_IBSS, WLAN_CAPABILITY_IBSS);
@@ -36,29 +33,51 @@ void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, gfp_t gfp)
 
        if (wdev->current_bss) {
                cfg80211_unhold_bss(wdev->current_bss);
-               cfg80211_put_bss(wdev->current_bss);
+               cfg80211_put_bss(&wdev->current_bss->pub);
        }
 
-       cfg80211_hold_bss(bss);
-       wdev->current_bss = bss;
-       memcpy(wdev->bssid, bssid, ETH_ALEN);
+       cfg80211_hold_bss(bss_from_pub(bss));
+       wdev->current_bss = bss_from_pub(bss);
 
-       nl80211_send_ibss_bssid(wiphy_to_dev(wdev->wiphy), dev, bssid, gfp);
+       nl80211_send_ibss_bssid(wiphy_to_dev(wdev->wiphy), dev, bssid,
+                               GFP_KERNEL);
 #ifdef CONFIG_WIRELESS_EXT
        memset(&wrqu, 0, sizeof(wrqu));
        memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN);
        wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
 #endif
 }
+
+void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, gfp_t gfp)
+{
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+       struct cfg80211_event *ev;
+       unsigned long flags;
+
+       ev = kzalloc(sizeof(*ev), gfp);
+       if (!ev)
+               return;
+
+       ev->type = EVENT_IBSS_JOINED;
+       memcpy(ev->cr.bssid, bssid, ETH_ALEN);
+
+       spin_lock_irqsave(&wdev->event_lock, flags);
+       list_add_tail(&ev->list, &wdev->event_list);
+       spin_unlock_irqrestore(&wdev->event_lock, flags);
+       schedule_work(&rdev->event_work);
+}
 EXPORT_SYMBOL(cfg80211_ibss_joined);
 
-int cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
-                      struct net_device *dev,
-                      struct cfg80211_ibss_params *params)
+int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
+                        struct net_device *dev,
+                        struct cfg80211_ibss_params *params)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
        int err;
 
+       ASSERT_WDEV_LOCK(wdev);
+
        if (wdev->ssid_len)
                return -EALREADY;
 
@@ -76,39 +95,82 @@ int cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
        return 0;
 }
 
-void cfg80211_clear_ibss(struct net_device *dev, bool nowext)
+int cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
+                      struct net_device *dev,
+                      struct cfg80211_ibss_params *params)
+{
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+       int err;
+
+       wdev_lock(wdev);
+       err = __cfg80211_join_ibss(rdev, dev, params);
+       wdev_unlock(wdev);
+
+       return err;
+}
+
+static void __cfg80211_clear_ibss(struct net_device *dev, bool nowext)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
 
+       ASSERT_WDEV_LOCK(wdev);
+
        if (wdev->current_bss) {
                cfg80211_unhold_bss(wdev->current_bss);
-               cfg80211_put_bss(wdev->current_bss);
+               cfg80211_put_bss(&wdev->current_bss->pub);
        }
 
        wdev->current_bss = NULL;
        wdev->ssid_len = 0;
-       memset(wdev->bssid, 0, ETH_ALEN);
 #ifdef CONFIG_WIRELESS_EXT
        if (!nowext)
                wdev->wext.ibss.ssid_len = 0;
 #endif
 }
 
-int cfg80211_leave_ibss(struct cfg80211_registered_device *rdev,
-                       struct net_device *dev, bool nowext)
+void cfg80211_clear_ibss(struct net_device *dev, bool nowext)
 {
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+
+       wdev_lock(wdev);
+       __cfg80211_clear_ibss(dev, nowext);
+       wdev_unlock(wdev);
+}
+
+static int __cfg80211_leave_ibss(struct cfg80211_registered_device *rdev,
+                                struct net_device *dev, bool nowext)
+{
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
        int err;
 
+       ASSERT_WDEV_LOCK(wdev);
+
+       if (!wdev->ssid_len)
+               return -ENOLINK;
+
        err = rdev->ops->leave_ibss(&rdev->wiphy, dev);
 
        if (err)
                return err;
 
-       cfg80211_clear_ibss(dev, nowext);
+       __cfg80211_clear_ibss(dev, nowext);
 
        return 0;
 }
 
+int cfg80211_leave_ibss(struct cfg80211_registered_device *rdev,
+                       struct net_device *dev, bool nowext)
+{
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+       int err;
+
+       wdev_lock(wdev);
+       err = __cfg80211_leave_ibss(rdev, dev, nowext);
+       wdev_unlock(wdev);
+
+       return err;
+}
+
 #ifdef CONFIG_WIRELESS_EXT
 static int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev,
                                   struct wireless_dev *wdev)
@@ -185,12 +247,15 @@ int cfg80211_ibss_wext_siwfreq(struct net_device *dev,
        if (wdev->wext.ibss.channel == chan)
                return 0;
 
-       if (wdev->ssid_len) {
-               err = cfg80211_leave_ibss(wiphy_to_dev(wdev->wiphy),
-                                         dev, true);
-               if (err)
-                       return err;
-       }
+       wdev_lock(wdev);
+       err = 0;
+       if (wdev->ssid_len)
+               err = __cfg80211_leave_ibss(wiphy_to_dev(wdev->wiphy),
+                                           dev, true);
+       wdev_unlock(wdev);
+
+       if (err)
+               return err;
 
        if (chan) {
                wdev->wext.ibss.channel = chan;
@@ -216,10 +281,12 @@ int cfg80211_ibss_wext_giwfreq(struct net_device *dev,
        if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC))
                return -EINVAL;
 
+       wdev_lock(wdev);
        if (wdev->current_bss)
-               chan = wdev->current_bss->channel;
+               chan = wdev->current_bss->pub.channel;
        else if (wdev->wext.ibss.channel)
                chan = wdev->wext.ibss.channel;
+       wdev_unlock(wdev);
 
        if (chan) {
                freq->m = chan->center_freq;
@@ -248,12 +315,15 @@ int cfg80211_ibss_wext_siwessid(struct net_device *dev,
        if (!wiphy_to_dev(wdev->wiphy)->ops->join_ibss)
                return -EOPNOTSUPP;
 
-       if (wdev->ssid_len) {
-               err = cfg80211_leave_ibss(wiphy_to_dev(wdev->wiphy),
-                                         dev, true);
-               if (err)
-                       return err;
-       }
+       wdev_lock(wdev);
+       err = 0;
+       if (wdev->ssid_len)
+               err = __cfg80211_leave_ibss(wiphy_to_dev(wdev->wiphy),
+                                           dev, true);
+       wdev_unlock(wdev);
+
+       if (err)
+               return err;
 
        /* iwconfig uses nul termination in SSID.. */
        if (len > 0 && ssid[len - 1] == '\0')
@@ -280,6 +350,7 @@ int cfg80211_ibss_wext_giwessid(struct net_device *dev,
 
        data->flags = 0;
 
+       wdev_lock(wdev);
        if (wdev->ssid_len) {
                data->flags = 1;
                data->length = wdev->ssid_len;
@@ -289,6 +360,7 @@ int cfg80211_ibss_wext_giwessid(struct net_device *dev,
                data->length = wdev->wext.ibss.ssid_len;
                memcpy(ssid, wdev->wext.ibss.ssid, data->length);
        }
+       wdev_unlock(wdev);
 
        return 0;
 }
@@ -326,12 +398,15 @@ int cfg80211_ibss_wext_siwap(struct net_device *dev,
            compare_ether_addr(bssid, wdev->wext.ibss.bssid) == 0)
                return 0;
 
-       if (wdev->ssid_len) {
-               err = cfg80211_leave_ibss(wiphy_to_dev(wdev->wiphy),
-                                         dev, true);
-               if (err)
-                       return err;
-       }
+       wdev_lock(wdev);
+       err = 0;
+       if (wdev->ssid_len)
+               err = __cfg80211_leave_ibss(wiphy_to_dev(wdev->wiphy),
+                                           dev, true);
+       wdev_unlock(wdev);
+
+       if (err)
+               return err;
 
        if (bssid) {
                memcpy(wdev->wext.bssid, bssid, ETH_ALEN);
@@ -356,12 +431,13 @@ int cfg80211_ibss_wext_giwap(struct net_device *dev,
 
        ap_addr->sa_family = ARPHRD_ETHER;
 
-       if (wdev->wext.ibss.bssid) {
+       wdev_lock(wdev);
+       if (wdev->current_bss)
+               memcpy(ap_addr->sa_data, wdev->current_bss->pub.bssid, ETH_ALEN);
+       else
                memcpy(ap_addr->sa_data, wdev->wext.ibss.bssid, ETH_ALEN);
-               return 0;
-       }
+       wdev_unlock(wdev);
 
-       memcpy(ap_addr->sa_data, wdev->bssid, ETH_ALEN);
        return 0;
 }
 /* temporary symbol - mark GPL - in the future the handler won't be */
index 4218436..1b2ca1f 100644 (file)
 
 void cfg80211_send_rx_auth(struct net_device *dev, const u8 *buf, size_t len)
 {
-       struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+       struct wiphy *wiphy = wdev->wiphy;
        struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
-       nl80211_send_rx_auth(rdev, dev, buf, len);
+       struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
+       u8 *bssid = mgmt->bssid;
+       int i;
+       u16 status = le16_to_cpu(mgmt->u.auth.status_code);
+       bool done = false;
+
+       wdev_lock(wdev);
+
+       for (i = 0; i < MAX_AUTH_BSSES; i++) {
+               if (wdev->authtry_bsses[i] &&
+                   memcmp(wdev->authtry_bsses[i]->pub.bssid, bssid,
+                                                       ETH_ALEN) == 0) {
+                       if (status == WLAN_STATUS_SUCCESS) {
+                               wdev->auth_bsses[i] = wdev->authtry_bsses[i];
+                       } else {
+                               cfg80211_unhold_bss(wdev->authtry_bsses[i]);
+                               cfg80211_put_bss(&wdev->authtry_bsses[i]->pub);
+                       }
+                       wdev->authtry_bsses[i] = NULL;
+                       done = true;
+                       break;
+               }
+       }
+
+       WARN_ON(!done);
+
+       nl80211_send_rx_auth(rdev, dev, buf, len, GFP_KERNEL);
+       cfg80211_sme_rx_auth(dev, buf, len);
+
+       wdev_unlock(wdev);
 }
 EXPORT_SYMBOL(cfg80211_send_rx_auth);
 
 void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len)
 {
-       struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
+       u16 status_code;
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+       struct wiphy *wiphy = wdev->wiphy;
        struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
-       nl80211_send_rx_assoc(rdev, dev, buf, len);
+       struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
+       u8 *ie = mgmt->u.assoc_resp.variable;
+       int i, ieoffs = offsetof(struct ieee80211_mgmt, u.assoc_resp.variable);
+       bool done;
+
+       wdev_lock(wdev);
+
+       status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code);
+
+       nl80211_send_rx_assoc(rdev, dev, buf, len, GFP_KERNEL);
+
+       __cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, ie, len - ieoffs,
+                                 status_code,
+                                 status_code == WLAN_STATUS_SUCCESS);
+
+       if (status_code == WLAN_STATUS_SUCCESS) {
+               for (i = 0; wdev->current_bss && i < MAX_AUTH_BSSES; i++) {
+                       if (wdev->auth_bsses[i] == wdev->current_bss) {
+                               cfg80211_unhold_bss(wdev->auth_bsses[i]);
+                               cfg80211_put_bss(&wdev->auth_bsses[i]->pub);
+                               wdev->auth_bsses[i] = NULL;
+                               done = true;
+                               break;
+                       }
+               }
+
+               WARN_ON(!done);
+       }
+
+       wdev_unlock(wdev);
 }
 EXPORT_SYMBOL(cfg80211_send_rx_assoc);
 
-void cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len)
+static void __cfg80211_send_deauth(struct net_device *dev,
+                                  const u8 *buf, size_t len)
 {
-       struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+       struct wiphy *wiphy = wdev->wiphy;
        struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
-       nl80211_send_deauth(rdev, dev, buf, len);
+       struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
+       const u8 *bssid = mgmt->bssid;
+       int i;
+       bool done = false;
+
+       ASSERT_WDEV_LOCK(wdev);
+
+       nl80211_send_deauth(rdev, dev, buf, len, GFP_KERNEL);
+
+       if (wdev->current_bss &&
+           memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0) {
+               done = true;
+               cfg80211_unhold_bss(wdev->current_bss);
+               cfg80211_put_bss(&wdev->current_bss->pub);
+               wdev->current_bss = NULL;
+       } else for (i = 0; i < MAX_AUTH_BSSES; i++) {
+               if (wdev->auth_bsses[i] &&
+                   memcmp(wdev->auth_bsses[i]->pub.bssid, bssid, ETH_ALEN) == 0) {
+                       cfg80211_unhold_bss(wdev->auth_bsses[i]);
+                       cfg80211_put_bss(&wdev->auth_bsses[i]->pub);
+                       wdev->auth_bsses[i] = NULL;
+                       done = true;
+                       break;
+               }
+               if (wdev->authtry_bsses[i] &&
+                   memcmp(wdev->authtry_bsses[i]->pub.bssid, bssid, ETH_ALEN) == 0) {
+                       cfg80211_unhold_bss(wdev->authtry_bsses[i]);
+                       cfg80211_put_bss(&wdev->authtry_bsses[i]->pub);
+                       wdev->authtry_bsses[i] = NULL;
+                       done = true;
+                       break;
+               }
+       }
+
+       WARN_ON(!done);
+
+       if (wdev->sme_state == CFG80211_SME_CONNECTED) {
+               u16 reason_code;
+               bool from_ap;
+
+               reason_code = le16_to_cpu(mgmt->u.deauth.reason_code);
+
+               from_ap = memcmp(mgmt->da, dev->dev_addr, ETH_ALEN) == 0;
+               __cfg80211_disconnected(dev, NULL, 0, reason_code, from_ap);
+       } else if (wdev->sme_state == CFG80211_SME_CONNECTING) {
+               __cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, NULL, 0,
+                                         WLAN_STATUS_UNSPECIFIED_FAILURE,
+                                         false);
+       }
+}
+
+
+void cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len,
+                         void *cookie)
+{
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+
+       BUG_ON(cookie && wdev != cookie);
+
+       if (cookie) {
+               /* called within callback */
+               __cfg80211_send_deauth(dev, buf, len);
+       } else {
+               wdev_lock(wdev);
+               __cfg80211_send_deauth(dev, buf, len);
+               wdev_unlock(wdev);
+       }
 }
 EXPORT_SYMBOL(cfg80211_send_deauth);
 
-void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len)
+static void __cfg80211_send_disassoc(struct net_device *dev,
+                                    const u8 *buf, size_t len)
 {
-       struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+       struct wiphy *wiphy = wdev->wiphy;
        struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
-       nl80211_send_disassoc(rdev, dev, buf, len);
+       struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
+       const u8 *bssid = mgmt->bssid;
+       int i;
+       u16 reason_code;
+       bool from_ap;
+       bool done = false;
+
+       wdev_lock(wdev);
+
+       nl80211_send_disassoc(rdev, dev, buf, len, GFP_KERNEL);
+
+       if (!wdev->sme_state == CFG80211_SME_CONNECTED)
+               goto out;
+
+       if (wdev->current_bss &&
+           memcmp(wdev->current_bss, bssid, ETH_ALEN) == 0) {
+               for (i = 0; i < MAX_AUTH_BSSES; i++) {
+                       if (wdev->authtry_bsses[i] || wdev->auth_bsses[i])
+                               continue;
+                       wdev->auth_bsses[i] = wdev->current_bss;
+                       wdev->current_bss = NULL;
+                       done = true;
+                       cfg80211_sme_disassoc(dev, i);
+                       break;
+               }
+               WARN_ON(!done);
+       } else
+               WARN_ON(1);
+
+
+       reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code);
+
+       from_ap = memcmp(mgmt->da, dev->dev_addr, ETH_ALEN) == 0;
+       __cfg80211_disconnected(dev, NULL, 0, reason_code, from_ap);
+ out:
+       wdev_unlock(wdev);
 }
-EXPORT_SYMBOL(cfg80211_send_disassoc);
 
-static void cfg80211_wext_disconnected(struct net_device *dev)
+void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len,
+                           void *cookie)
 {
-#ifdef CONFIG_WIRELESS_EXT
-       union iwreq_data wrqu;
-       memset(&wrqu, 0, sizeof(wrqu));
-       wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
-#endif
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+
+       BUG_ON(cookie && wdev != cookie);
+
+       if (cookie) {
+               /* called within callback */
+               __cfg80211_send_disassoc(dev, buf, len);
+       } else {
+               wdev_lock(wdev);
+               __cfg80211_send_disassoc(dev, buf, len);
+               wdev_unlock(wdev);
+       }
 }
+EXPORT_SYMBOL(cfg80211_send_disassoc);
 
 void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr)
 {
-       struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+       struct wiphy *wiphy = wdev->wiphy;
        struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
-       nl80211_send_auth_timeout(rdev, dev, addr);
-       cfg80211_wext_disconnected(dev);
+       int i;
+       bool done = false;
+
+       wdev_lock(wdev);
+
+       nl80211_send_auth_timeout(rdev, dev, addr, GFP_KERNEL);
+       if (wdev->sme_state == CFG80211_SME_CONNECTING)
+               __cfg80211_connect_result(dev, addr, NULL, 0, NULL, 0,
+                                         WLAN_STATUS_UNSPECIFIED_FAILURE,
+                                         false);
+
+       for (i = 0; addr && i < MAX_AUTH_BSSES; i++) {
+               if (wdev->authtry_bsses[i] &&
+                   memcmp(wdev->authtry_bsses[i]->pub.bssid,
+                          addr, ETH_ALEN) == 0) {
+                       cfg80211_unhold_bss(wdev->authtry_bsses[i]);
+                       cfg80211_put_bss(&wdev->authtry_bsses[i]->pub);
+                       wdev->authtry_bsses[i] = NULL;
+                       done = true;
+                       break;
+               }
+       }
+
+       WARN_ON(!done);
+
+       wdev_unlock(wdev);
 }
 EXPORT_SYMBOL(cfg80211_send_auth_timeout);
 
 void cfg80211_send_assoc_timeout(struct net_device *dev, const u8 *addr)
 {
-       struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+       struct wiphy *wiphy = wdev->wiphy;
        struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
-       nl80211_send_assoc_timeout(rdev, dev, addr);
-       cfg80211_wext_disconnected(dev);
+       int i;
+       bool done = false;
+
+       wdev_lock(wdev);
+
+       nl80211_send_assoc_timeout(rdev, dev, addr, GFP_KERNEL);
+       if (wdev->sme_state == CFG80211_SME_CONNECTING)
+               __cfg80211_connect_result(dev, addr, NULL, 0, NULL, 0,
+                                         WLAN_STATUS_UNSPECIFIED_FAILURE,
+                                         false);
+
+       for (i = 0; addr && i < MAX_AUTH_BSSES; i++) {
+               if (wdev->auth_bsses[i] &&
+                   memcmp(wdev->auth_bsses[i]->pub.bssid,
+                          addr, ETH_ALEN) == 0) {
+                       cfg80211_unhold_bss(wdev->auth_bsses[i]);
+                       cfg80211_put_bss(&wdev->auth_bsses[i]->pub);
+                       wdev->auth_bsses[i] = NULL;
+                       done = true;
+                       break;
+               }
+       }
+
+       WARN_ON(!done);
+
+       wdev_unlock(wdev);
 }
 EXPORT_SYMBOL(cfg80211_send_assoc_timeout);
 
 void cfg80211_michael_mic_failure(struct net_device *dev, const u8 *addr,
                                  enum nl80211_key_type key_type, int key_id,
-                                 const u8 *tsc)
+                                 const u8 *tsc, gfp_t gfp)
 {
        struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
        struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
-       nl80211_michael_mic_failure(rdev, dev, addr, key_type, key_id, tsc);
+#ifdef CONFIG_WIRELESS_EXT
+       union iwreq_data wrqu;
+       char *buf = kmalloc(128, gfp);
+
+       if (buf) {
+               sprintf(buf, "MLME-MICHAELMICFAILURE.indication("
+                       "keyid=%d %scast addr=%pM)", key_id,
+                       key_type == NL80211_KEYTYPE_GROUP ? "broad" : "uni",
+                       addr);
+               memset(&wrqu, 0, sizeof(wrqu));
+               wrqu.data.length = strlen(buf);
+               wireless_send_event(dev, IWEVCUSTOM, &wrqu, buf);
+               kfree(buf);
+       }
+#endif
+
+       nl80211_michael_mic_failure(rdev, dev, addr, key_type, key_id, tsc, gfp);
 }
 EXPORT_SYMBOL(cfg80211_michael_mic_failure);
+
+/* some MLME handling for userspace SME */
+int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
+                        struct net_device *dev,
+                        struct ieee80211_channel *chan,
+                        enum nl80211_auth_type auth_type,
+                        const u8 *bssid,
+                        const u8 *ssid, int ssid_len,
+                        const u8 *ie, int ie_len)
+{
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+       struct cfg80211_auth_request req;
+       struct cfg80211_internal_bss *bss;
+       int i, err, slot = -1, nfree = 0;
+
+       ASSERT_WDEV_LOCK(wdev);
+
+       if (wdev->current_bss &&
+           memcmp(bssid, wdev->current_bss->pub.bssid, ETH_ALEN) == 0)
+               return -EALREADY;
+
+       for (i = 0; i < MAX_AUTH_BSSES; i++) {
+               if (wdev->authtry_bsses[i] &&
+                   memcmp(bssid, wdev->authtry_bsses[i]->pub.bssid,
+                                               ETH_ALEN) == 0)
+                       return -EALREADY;
+               if (wdev->auth_bsses[i] &&
+                   memcmp(bssid, wdev->auth_bsses[i]->pub.bssid,
+                                               ETH_ALEN) == 0)
+                       return -EALREADY;
+       }
+
+       memset(&req, 0, sizeof(req));
+
+       req.ie = ie;
+       req.ie_len = ie_len;
+       req.auth_type = auth_type;
+       req.bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len,
+                                  WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
+       if (!req.bss)
+               return -ENOENT;
+
+       bss = bss_from_pub(req.bss);
+
+       for (i = 0; i < MAX_AUTH_BSSES; i++) {
+               if (!wdev->auth_bsses[i] && !wdev->authtry_bsses[i]) {
+                       slot = i;
+                       nfree++;
+               }
+       }
+
+       /* we need one free slot for disassoc and one for this auth */
+       if (nfree < 2) {
+               err = -ENOSPC;
+               goto out;
+       }
+
+       wdev->authtry_bsses[slot] = bss;
+       cfg80211_hold_bss(bss);
+
+       err = rdev->ops->auth(&rdev->wiphy, dev, &req);
+       if (err) {
+               wdev->authtry_bsses[slot] = NULL;
+               cfg80211_unhold_bss(bss);
+       }
+
+ out:
+       if (err)
+               cfg80211_put_bss(req.bss);
+       return err;
+}
+
+int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
+                      struct net_device *dev, struct ieee80211_channel *chan,
+                      enum nl80211_auth_type auth_type, const u8 *bssid,
+                      const u8 *ssid, int ssid_len,
+                      const u8 *ie, int ie_len)
+{
+       int err;
+
+       wdev_lock(dev->ieee80211_ptr);
+       err = __cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid,
+                                  ssid, ssid_len, ie, ie_len);
+       wdev_unlock(dev->ieee80211_ptr);
+
+       return err;
+}
+
+int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
+                         struct net_device *dev,
+                         struct ieee80211_channel *chan,
+                         const u8 *bssid, const u8 *prev_bssid,
+                         const u8 *ssid, int ssid_len,
+                         const u8 *ie, int ie_len, bool use_mfp,
+                         struct cfg80211_crypto_settings *crypt)
+{
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+       struct cfg80211_assoc_request req;
+       struct cfg80211_internal_bss *bss;
+       int i, err, slot = -1;
+
+       ASSERT_WDEV_LOCK(wdev);
+
+       memset(&req, 0, sizeof(req));
+
+       if (wdev->current_bss)
+               return -EALREADY;
+
+       req.ie = ie;
+       req.ie_len = ie_len;
+       memcpy(&req.crypto, crypt, sizeof(req.crypto));
+       req.use_mfp = use_mfp;
+       req.prev_bssid = prev_bssid;
+       req.bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len,
+                                  WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
+       if (!req.bss)
+               return -ENOENT;
+
+       bss = bss_from_pub(req.bss);
+
+       for (i = 0; i < MAX_AUTH_BSSES; i++) {
+               if (bss == wdev->auth_bsses[i]) {
+                       slot = i;
+                       break;
+               }
+       }
+
+       if (slot < 0) {
+               err = -ENOTCONN;
+               goto out;
+       }
+
+       err = rdev->ops->assoc(&rdev->wiphy, dev, &req);
+ out:
+       /* still a reference in wdev->auth_bsses[slot] */
+       cfg80211_put_bss(req.bss);
+       return err;
+}
+
+int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
+                       struct net_device *dev,
+                       struct ieee80211_channel *chan,
+                       const u8 *bssid, const u8 *prev_bssid,
+                       const u8 *ssid, int ssid_len,
+                       const u8 *ie, int ie_len, bool use_mfp,
+                       struct cfg80211_crypto_settings *crypt)
+{
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+       int err;
+
+       wdev_lock(wdev);
+       err = __cfg80211_mlme_assoc(rdev, dev, chan, bssid, prev_bssid,
+                                   ssid, ssid_len, ie, ie_len, use_mfp, crypt);
+       wdev_unlock(wdev);
+
+       return err;
+}
+
+int __cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev,
+                          struct net_device *dev, const u8 *bssid,
+                          const u8 *ie, int ie_len, u16 reason)
+{
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+       struct cfg80211_deauth_request req;
+       int i;
+
+       ASSERT_WDEV_LOCK(wdev);
+
+       memset(&req, 0, sizeof(req));
+       req.reason_code = reason;
+       req.ie = ie;
+       req.ie_len = ie_len;
+       if (wdev->current_bss &&
+           memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0) {
+               req.bss = &wdev->current_bss->pub;
+       } else for (i = 0; i < MAX_AUTH_BSSES; i++) {
+               if (wdev->auth_bsses[i] &&
+                   memcmp(bssid, wdev->auth_bsses[i]->pub.bssid, ETH_ALEN) == 0) {
+                       req.bss = &wdev->auth_bsses[i]->pub;
+                       break;
+               }
+               if (wdev->authtry_bsses[i] &&
+                   memcmp(bssid, wdev->authtry_bsses[i]->pub.bssid, ETH_ALEN) == 0) {
+                       req.bss = &wdev->authtry_bsses[i]->pub;
+                       break;
+               }
+       }
+
+       if (!req.bss)
+               return -ENOTCONN;
+
+       return rdev->ops->deauth(&rdev->wiphy, dev, &req, wdev);
+}
+
+int cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev,
+                        struct net_device *dev, const u8 *bssid,
+                        const u8 *ie, int ie_len, u16 reason)
+{
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+       int err;
+
+       wdev_lock(wdev);
+       err = __cfg80211_mlme_deauth(rdev, dev, bssid, ie, ie_len, reason);
+       wdev_unlock(wdev);
+
+       return err;
+}
+
+static int __cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev,
+                                   struct net_device *dev, const u8 *bssid,
+                                   const u8 *ie, int ie_len, u16 reason)
+{
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+       struct cfg80211_disassoc_request req;
+
+       ASSERT_WDEV_LOCK(wdev);
+
+       memset(&req, 0, sizeof(req));
+       req.reason_code = reason;
+       req.ie = ie;
+       req.ie_len = ie_len;
+       if (memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0)
+               req.bss = &wdev->current_bss->pub;
+       else
+               return -ENOTCONN;
+
+       return rdev->ops->disassoc(&rdev->wiphy, dev, &req, wdev);
+}
+
+int cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev,
+                          struct net_device *dev, const u8 *bssid,
+                          const u8 *ie, int ie_len, u16 reason)
+{
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+       int err;
+
+       wdev_lock(wdev);
+       err = __cfg80211_mlme_disassoc(rdev, dev, bssid, ie, ie_len, reason);
+       wdev_unlock(wdev);
+
+       return err;
+}
+
+void cfg80211_mlme_down(struct cfg80211_registered_device *rdev,
+                       struct net_device *dev)
+{
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+       struct cfg80211_deauth_request req;
+       int i;
+
+       ASSERT_WDEV_LOCK(wdev);
+
+       if (!rdev->ops->deauth)
+               return;
+
+       memset(&req, 0, sizeof(req));
+       req.reason_code = WLAN_REASON_DEAUTH_LEAVING;
+       req.ie = NULL;
+       req.ie_len = 0;
+
+       if (wdev->current_bss) {
+               req.bss = &wdev->current_bss->pub;
+               rdev->ops->deauth(&rdev->wiphy, dev, &req, wdev);
+               if (wdev->current_bss) {
+                       cfg80211_unhold_bss(wdev->current_bss);
+                       cfg80211_put_bss(&wdev->current_bss->pub);
+                       wdev->current_bss = NULL;
+               }
+       }
+
+       for (i = 0; i < MAX_AUTH_BSSES; i++) {
+               if (wdev->auth_bsses[i]) {
+                       req.bss = &wdev->auth_bsses[i]->pub;
+                       rdev->ops->deauth(&rdev->wiphy, dev, &req, wdev);
+                       if (wdev->auth_bsses[i]) {
+                               cfg80211_unhold_bss(wdev->auth_bsses[i]);
+                               cfg80211_put_bss(&wdev->auth_bsses[i]->pub);
+                               wdev->auth_bsses[i] = NULL;
+                       }
+               }
+               if (wdev->authtry_bsses[i]) {
+                       req.bss = &wdev->authtry_bsses[i]->pub;
+                       rdev->ops->deauth(&rdev->wiphy, dev, &req, wdev);
+                       if (wdev->authtry_bsses[i]) {
+                               cfg80211_unhold_bss(wdev->authtry_bsses[i]);
+                               cfg80211_put_bss(&wdev->authtry_bsses[i]->pub);
+                               wdev->authtry_bsses[i] = NULL;
+                       }
+               }
+       }
+}
index 634496b..4478760 100644 (file)
@@ -29,9 +29,9 @@ static struct genl_family nl80211_fam = {
        .maxattr = NL80211_ATTR_MAX,
 };
 
-/* internal helper: get drv and dev */
-static int get_drv_dev_by_info_ifindex(struct nlattr **attrs,
-                                      struct cfg80211_registered_device **drv,
+/* internal helper: get rdev and dev */
+static int get_rdev_dev_by_info_ifindex(struct nlattr **attrs,
+                                      struct cfg80211_registered_device **rdev,
                                       struct net_device **dev)
 {
        int ifindex;
@@ -44,10 +44,10 @@ static int get_drv_dev_by_info_ifindex(struct nlattr **attrs,
        if (!*dev)
                return -ENODEV;
 
-       *drv = cfg80211_get_dev_from_ifindex(ifindex);
-       if (IS_ERR(*drv)) {
+       *rdev = cfg80211_get_dev_from_ifindex(ifindex);
+       if (IS_ERR(*rdev)) {
                dev_put(*dev);
-               return PTR_ERR(*drv);
+               return PTR_ERR(*rdev);
        }
 
        return 0;
@@ -71,6 +71,7 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = {
        [NL80211_ATTR_IFNAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ-1 },
 
        [NL80211_ATTR_MAC] = { .type = NLA_BINARY, .len = ETH_ALEN },
+       [NL80211_ATTR_PREV_BSSID] = { .type = NLA_BINARY, .len = ETH_ALEN },
 
        [NL80211_ATTR_KEY_DATA] = { .type = NLA_BINARY,
                                    .len = WLAN_MAX_KEY_LEN },
@@ -128,6 +129,9 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = {
                .len = sizeof(struct nl80211_sta_flag_update),
        },
        [NL80211_ATTR_CONTROL_PORT] = { .type = NLA_FLAG },
+       [NL80211_ATTR_PRIVACY] = { .type = NLA_FLAG },
+       [NL80211_ATTR_CIPHER_SUITE_GROUP] = { .type = NLA_U32 },
+       [NL80211_ATTR_WPA_VERSIONS] = { .type = NLA_U32 },
 };
 
 /* IE validation */
@@ -347,6 +351,17 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
        CMD(join_ibss, JOIN_IBSS);
 
 #undef CMD
+
+       if (dev->ops->connect || dev->ops->auth) {
+               i++;
+               NLA_PUT_U32(msg, i, NL80211_CMD_CONNECT);
+       }
+
+       if (dev->ops->disconnect || dev->ops->deauth) {
+               i++;
+               NLA_PUT_U32(msg, i, NL80211_CMD_DISCONNECT);
+       }
+
        nla_nest_end(msg, nl_cmds);
 
        return genlmsg_end(msg, hdr);
@@ -363,7 +378,7 @@ static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb)
        struct cfg80211_registered_device *dev;
 
        mutex_lock(&cfg80211_mutex);
-       list_for_each_entry(dev, &cfg80211_drv_list, list) {
+       list_for_each_entry(dev, &cfg80211_rdev_list, list) {
                if (++idx <= start)
                        continue;
                if (nl80211_send_wiphy(skb, NETLINK_CB(cb->skb).pid,
@@ -396,14 +411,14 @@ static int nl80211_get_wiphy(struct sk_buff *skb, struct genl_info *info)
        if (nl80211_send_wiphy(msg, info->snd_pid, info->snd_seq, 0, dev) < 0)
                goto out_free;
 
-       cfg80211_put_dev(dev);
+       cfg80211_unlock_rdev(dev);
 
-       return genlmsg_unicast(msg, info->snd_pid);
+       return genlmsg_reply(msg, info);
 
  out_free:
        nlmsg_free(msg);
  out_err:
-       cfg80211_put_dev(dev);
+       cfg80211_unlock_rdev(dev);
        return -ENOBUFS;
 }
 
@@ -445,7 +460,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
 
        mutex_lock(&cfg80211_mutex);
 
-       rdev = __cfg80211_drv_from_info(info);
+       rdev = __cfg80211_rdev_from_info(info);
        if (IS_ERR(rdev)) {
                mutex_unlock(&cfg80211_mutex);
                result = PTR_ERR(rdev);
@@ -668,7 +683,7 @@ static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback *
        struct wireless_dev *wdev;
 
        mutex_lock(&cfg80211_mutex);
-       list_for_each_entry(dev, &cfg80211_drv_list, list) {
+       list_for_each_entry(dev, &cfg80211_rdev_list, list) {
                if (wp_idx < wp_start) {
                        wp_idx++;
                        continue;
@@ -709,7 +724,7 @@ static int nl80211_get_interface(struct sk_buff *skb, struct genl_info *info)
        struct net_device *netdev;
        int err;
 
-       err = get_drv_dev_by_info_ifindex(info->attrs, &dev, &netdev);
+       err = get_rdev_dev_by_info_ifindex(info->attrs, &dev, &netdev);
        if (err)
                return err;
 
@@ -722,15 +737,15 @@ static int nl80211_get_interface(struct sk_buff *skb, struct genl_info *info)
                goto out_free;
 
        dev_put(netdev);
-       cfg80211_put_dev(dev);
+       cfg80211_unlock_rdev(dev);
 
-       return genlmsg_unicast(msg, info->snd_pid);
+       return genlmsg_reply(msg, info);
 
  out_free:
        nlmsg_free(msg);
  out_err:
        dev_put(netdev);
-       cfg80211_put_dev(dev);
+       cfg80211_unlock_rdev(dev);
        return -ENOBUFS;
 }
 
@@ -765,9 +780,9 @@ static int parse_monitor_flags(struct nlattr *nla, u32 *mntrflags)
 
 static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
 {
-       struct cfg80211_registered_device *drv;
+       struct cfg80211_registered_device *rdev;
        struct vif_params params;
-       int err, ifindex;
+       int err;
        enum nl80211_iftype otype, ntype;
        struct net_device *dev;
        u32 _flags, *flags = NULL;
@@ -777,13 +792,11 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
 
        rtnl_lock();
 
-       err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
+       err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev);
        if (err)
                goto unlock_rtnl;
 
-       ifindex = dev->ifindex;
        otype = ntype = dev->ieee80211_ptr->iftype;
-       dev_put(dev);
 
        if (info->attrs[NL80211_ATTR_IFTYPE]) {
                ntype = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]);
@@ -795,8 +808,8 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
                }
        }
 
-       if (!drv->ops->change_virtual_intf ||
-           !(drv->wiphy.interface_modes & (1 << ntype))) {
+       if (!rdev->ops->change_virtual_intf ||
+           !(rdev->wiphy.interface_modes & (1 << ntype))) {
                err = -EOPNOTSUPP;
                goto unlock;
        }
@@ -826,21 +839,21 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
        }
 
        if (change)
-               err = drv->ops->change_virtual_intf(&drv->wiphy, ifindex,
+               err = rdev->ops->change_virtual_intf(&rdev->wiphy, dev,
                                                    ntype, flags, &params);
        else
                err = 0;
 
-       dev = __dev_get_by_index(&init_net, ifindex);
-       WARN_ON(!dev || (!err && dev->ieee80211_ptr->iftype != ntype));
+       WARN_ON(!err && dev->ieee80211_ptr->iftype != ntype);
 
-       if (dev && !err && (ntype != otype)) {
+       if (!err && (ntype != otype)) {
                if (otype == NL80211_IFTYPE_ADHOC)
                        cfg80211_clear_ibss(dev, false);
        }
 
  unlock:
-       cfg80211_put_dev(drv);
+       dev_put(dev);
+       cfg80211_unlock_rdev(rdev);
  unlock_rtnl:
        rtnl_unlock();
        return err;
@@ -848,7 +861,7 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
 
 static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
 {
-       struct cfg80211_registered_device *drv;
+       struct cfg80211_registered_device *rdev;
        struct vif_params params;
        int err;
        enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED;
@@ -867,14 +880,14 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
 
        rtnl_lock();
 
-       drv = cfg80211_get_dev_from_info(info);
-       if (IS_ERR(drv)) {
-               err = PTR_ERR(drv);
+       rdev = cfg80211_get_dev_from_info(info);
+       if (IS_ERR(rdev)) {
+               err = PTR_ERR(rdev);
                goto unlock_rtnl;
        }
 
-       if (!drv->ops->add_virtual_intf ||
-           !(drv->wiphy.interface_modes & (1 << type))) {
+       if (!rdev->ops->add_virtual_intf ||
+           !(rdev->wiphy.interface_modes & (1 << type))) {
                err = -EOPNOTSUPP;
                goto unlock;
        }
@@ -888,12 +901,12 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
        err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ?
                                  info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL,
                                  &flags);
-       err = drv->ops->add_virtual_intf(&drv->wiphy,
+       err = rdev->ops->add_virtual_intf(&rdev->wiphy,
                nla_data(info->attrs[NL80211_ATTR_IFNAME]),
                type, err ? NULL : &flags, &params);
 
  unlock:
-       cfg80211_put_dev(drv);
+       cfg80211_unlock_rdev(rdev);
  unlock_rtnl:
        rtnl_unlock();
        return err;
@@ -901,27 +914,27 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
 
 static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info)
 {
-       struct cfg80211_registered_device *drv;
+       struct cfg80211_registered_device *rdev;
        int ifindex, err;
        struct net_device *dev;
 
        rtnl_lock();
 
-       err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
+       err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev);
        if (err)
                goto unlock_rtnl;
        ifindex = dev->ifindex;
        dev_put(dev);
 
-       if (!drv->ops->del_virtual_intf) {
+       if (!rdev->ops->del_virtual_intf) {
                err = -EOPNOTSUPP;
                goto out;
        }
 
-       err = drv->ops->del_virtual_intf(&drv->wiphy, ifindex);
+       err = rdev->ops->del_virtual_intf(&rdev->wiphy, ifindex);
 
  out:
-       cfg80211_put_dev(drv);
+       cfg80211_unlock_rdev(rdev);
  unlock_rtnl:
        rtnl_unlock();
        return err;
@@ -955,7 +968,7 @@ static void get_key_callback(void *c, struct key_params *params)
 
 static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info)
 {
-       struct cfg80211_registered_device *drv;
+       struct cfg80211_registered_device *rdev;
        int err;
        struct net_device *dev;
        u8 key_idx = 0;
@@ -977,11 +990,11 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info)
 
        rtnl_lock();
 
-       err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
+       err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev);
        if (err)
                goto unlock_rtnl;
 
-       if (!drv->ops->get_key) {
+       if (!rdev->ops->get_key) {
                err = -EOPNOTSUPP;
                goto out;
        }
@@ -1007,7 +1020,7 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info)
        if (mac_addr)
                NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr);
 
-       err = drv->ops->get_key(&drv->wiphy, dev, key_idx, mac_addr,
+       err = rdev->ops->get_key(&rdev->wiphy, dev, key_idx, mac_addr,
                                &cookie, get_key_callback);
 
        if (err)
@@ -1017,7 +1030,7 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info)
                goto nla_put_failure;
 
        genlmsg_end(msg, hdr);
-       err = genlmsg_unicast(msg, info->snd_pid);
+       err = genlmsg_reply(msg, info);
        goto out;
 
  nla_put_failure:
@@ -1025,7 +1038,7 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info)
  free_msg:
        nlmsg_free(msg);
  out:
-       cfg80211_put_dev(drv);
+       cfg80211_unlock_rdev(rdev);
        dev_put(dev);
  unlock_rtnl:
        rtnl_unlock();
@@ -1035,7 +1048,7 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info)
 
 static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info)
 {
-       struct cfg80211_registered_device *drv;
+       struct cfg80211_registered_device *rdev;
        int err;
        struct net_device *dev;
        u8 key_idx;
@@ -1060,24 +1073,24 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info)
 
        rtnl_lock();
 
-       err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
+       err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev);
        if (err)
                goto unlock_rtnl;
 
        if (info->attrs[NL80211_ATTR_KEY_DEFAULT])
-               func = drv->ops->set_default_key;
+               func = rdev->ops->set_default_key;
        else
-               func = drv->ops->set_default_mgmt_key;
+               func = rdev->ops->set_default_mgmt_key;
 
        if (!func) {
                err = -EOPNOTSUPP;
                goto out;
        }
 
-       err = func(&drv->wiphy, dev, key_idx);
+       err = func(&rdev->wiphy, dev, key_idx);
 #ifdef CONFIG_WIRELESS_EXT
        if (!err) {
-               if (func == drv->ops->set_default_key)
+               if (func == rdev->ops->set_default_key)
                        dev->ieee80211_ptr->wext.default_key = key_idx;
                else
                        dev->ieee80211_ptr->wext.default_mgmt_key = key_idx;
@@ -1085,7 +1098,7 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info)
 #endif
 
  out:
-       cfg80211_put_dev(drv);
+       cfg80211_unlock_rdev(rdev);
        dev_put(dev);
 
  unlock_rtnl:
@@ -1096,7 +1109,7 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info)
 
 static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info)
 {
-       struct cfg80211_registered_device *drv;
+       struct cfg80211_registered_device *rdev;
        int err, i;
        struct net_device *dev;
        struct key_params params;
@@ -1131,27 +1144,27 @@ static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info)
 
        rtnl_lock();
 
-       err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
+       err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev);
        if (err)
                goto unlock_rtnl;
 
-       for (i = 0; i < drv->wiphy.n_cipher_suites; i++)
-               if (params.cipher == drv->wiphy.cipher_suites[i])
+       for (i = 0; i < rdev->wiphy.n_cipher_suites; i++)
+               if (params.cipher == rdev->wiphy.cipher_suites[i])
                        break;
-       if (i == drv->wiphy.n_cipher_suites) {
+       if (i == rdev->wiphy.n_cipher_suites) {
                err = -EINVAL;
                goto out;
        }
 
-       if (!drv->ops->add_key) {
+       if (!rdev->ops->add_key) {
                err = -EOPNOTSUPP;
                goto out;
        }
 
-       err = drv->ops->add_key(&drv->wiphy, dev, key_idx, mac_addr, &params);
+       err = rdev->ops->add_key(&rdev->wiphy, dev, key_idx, mac_addr, &params);
 
  out:
-       cfg80211_put_dev(drv);
+       cfg80211_unlock_rdev(rdev);
        dev_put(dev);
  unlock_rtnl:
        rtnl_unlock();
@@ -1161,7 +1174,7 @@ static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info)
 
 static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info)
 {
-       struct cfg80211_registered_device *drv;
+       struct cfg80211_registered_device *rdev;
        int err;
        struct net_device *dev;
        u8 key_idx = 0;
@@ -1178,16 +1191,16 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info)
 
        rtnl_lock();
 
-       err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
+       err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev);
        if (err)
                goto unlock_rtnl;
 
-       if (!drv->ops->del_key) {
+       if (!rdev->ops->del_key) {
                err = -EOPNOTSUPP;
                goto out;
        }
 
-       err = drv->ops->del_key(&drv->wiphy, dev, key_idx, mac_addr);
+       err = rdev->ops->del_key(&rdev->wiphy, dev, key_idx, mac_addr);
 
 #ifdef CONFIG_WIRELESS_EXT
        if (!err) {
@@ -1199,7 +1212,7 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info)
 #endif
 
  out:
-       cfg80211_put_dev(drv);
+       cfg80211_unlock_rdev(rdev);
        dev_put(dev);
 
  unlock_rtnl:
@@ -1212,7 +1225,7 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info)
 {
         int (*call)(struct wiphy *wiphy, struct net_device *dev,
                    struct beacon_parameters *info);
-       struct cfg80211_registered_device *drv;
+       struct cfg80211_registered_device *rdev;
        int err;
        struct net_device *dev;
        struct beacon_parameters params;
@@ -1223,7 +1236,7 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info)
 
        rtnl_lock();
 
-       err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
+       err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev);
        if (err)
                goto unlock_rtnl;
 
@@ -1242,10 +1255,10 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info)
                        goto out;
                }
 
-               call = drv->ops->add_beacon;
+               call = rdev->ops->add_beacon;
                break;
        case NL80211_CMD_SET_BEACON:
-               call = drv->ops->set_beacon;
+               call = rdev->ops->set_beacon;
                break;
        default:
                WARN_ON(1);
@@ -1291,10 +1304,10 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info)
                goto out;
        }
 
-       err = call(&drv->wiphy, dev, &params);
+       err = call(&rdev->wiphy, dev, &params);
 
  out:
-       cfg80211_put_dev(drv);
+       cfg80211_unlock_rdev(rdev);
        dev_put(dev);
  unlock_rtnl:
        rtnl_unlock();
@@ -1304,17 +1317,17 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info)
 
 static int nl80211_del_beacon(struct sk_buff *skb, struct genl_info *info)
 {
-       struct cfg80211_registered_device *drv;
+       struct cfg80211_registered_device *rdev;
        int err;
        struct net_device *dev;
 
        rtnl_lock();
 
-       err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
+       err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev);
        if (err)
                goto unlock_rtnl;
 
-       if (!drv->ops->del_beacon) {
+       if (!rdev->ops->del_beacon) {
                err = -EOPNOTSUPP;
                goto out;
        }
@@ -1323,10 +1336,10 @@ static int nl80211_del_beacon(struct sk_buff *skb, struct genl_info *info)
                err = -EOPNOTSUPP;
                goto out;
        }
-       err = drv->ops->del_beacon(&drv->wiphy, dev);
+       err = rdev->ops->del_beacon(&rdev->wiphy, dev);
 
  out:
-       cfg80211_put_dev(drv);
+       cfg80211_unlock_rdev(rdev);
        dev_put(dev);
  unlock_rtnl:
        rtnl_unlock();
@@ -1560,7 +1573,7 @@ static int nl80211_dump_station(struct sk_buff *skb,
        cb->args[1] = sta_idx;
        err = skb->len;
  out_err:
-       cfg80211_put_dev(dev);
+       cfg80211_unlock_rdev(dev);
  out_rtnl:
        rtnl_unlock();
 
@@ -1569,7 +1582,7 @@ static int nl80211_dump_station(struct sk_buff *skb,
 
 static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info)
 {
-       struct cfg80211_registered_device *drv;
+       struct cfg80211_registered_device *rdev;
        int err;
        struct net_device *dev;
        struct station_info sinfo;
@@ -1585,16 +1598,16 @@ static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info)
 
        rtnl_lock();
 
-       err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
+       err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev);
        if (err)
                goto out_rtnl;
 
-       if (!drv->ops->get_station) {
+       if (!rdev->ops->get_station) {
                err = -EOPNOTSUPP;
                goto out;
        }
 
-       err = drv->ops->get_station(&drv->wiphy, dev, mac_addr, &sinfo);
+       err = rdev->ops->get_station(&rdev->wiphy, dev, mac_addr, &sinfo);
        if (err)
                goto out;
 
@@ -1606,13 +1619,13 @@ static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info)
                                 dev, mac_addr, &sinfo) < 0)
                goto out_free;
 
-       err = genlmsg_unicast(msg, info->snd_pid);
+       err = genlmsg_reply(msg, info);
        goto out;
 
  out_free:
        nlmsg_free(msg);
  out:
-       cfg80211_put_dev(drv);
+       cfg80211_unlock_rdev(rdev);
        dev_put(dev);
  out_rtnl:
        rtnl_unlock();
@@ -1643,7 +1656,7 @@ static int get_vlan(struct nlattr *vlanattr,
 
 static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
 {
-       struct cfg80211_registered_device *drv;
+       struct cfg80211_registered_device *rdev;
        int err;
        struct net_device *dev;
        struct station_parameters params;
@@ -1685,11 +1698,11 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
 
        rtnl_lock();
 
-       err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
+       err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev);
        if (err)
                goto out_rtnl;
 
-       err = get_vlan(info->attrs[NL80211_ATTR_STA_VLAN], drv, &params.vlan);
+       err = get_vlan(info->attrs[NL80211_ATTR_STA_VLAN], rdev, &params.vlan);
        if (err)
                goto out;
 
@@ -1738,17 +1751,17 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
        if (err)
                goto out;
 
-       if (!drv->ops->change_station) {
+       if (!rdev->ops->change_station) {
                err = -EOPNOTSUPP;
                goto out;
        }
 
-       err = drv->ops->change_station(&drv->wiphy, dev, mac_addr, &params);
+       err = rdev->ops->change_station(&rdev->wiphy, dev, mac_addr, &params);
 
  out:
        if (params.vlan)
                dev_put(params.vlan);
-       cfg80211_put_dev(drv);
+       cfg80211_unlock_rdev(rdev);
        dev_put(dev);
  out_rtnl:
        rtnl_unlock();
@@ -1758,7 +1771,7 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
 
 static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
 {
-       struct cfg80211_registered_device *drv;
+       struct cfg80211_registered_device *rdev;
        int err;
        struct net_device *dev;
        struct station_parameters params;
@@ -1798,11 +1811,11 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
 
        rtnl_lock();
 
-       err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
+       err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev);
        if (err)
                goto out_rtnl;
 
-       err = get_vlan(info->attrs[NL80211_ATTR_STA_VLAN], drv, &params.vlan);
+       err = get_vlan(info->attrs[NL80211_ATTR_STA_VLAN], rdev, &params.vlan);
        if (err)
                goto out;
 
@@ -1838,7 +1851,7 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
        if (err)
                goto out;
 
-       if (!drv->ops->add_station) {
+       if (!rdev->ops->add_station) {
                err = -EOPNOTSUPP;
                goto out;
        }
@@ -1848,12 +1861,12 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
                goto out;
        }
 
-       err = drv->ops->add_station(&drv->wiphy, dev, mac_addr, &params);
+       err = rdev->ops->add_station(&rdev->wiphy, dev, mac_addr, &params);
 
  out:
        if (params.vlan)
                dev_put(params.vlan);
-       cfg80211_put_dev(drv);
+       cfg80211_unlock_rdev(rdev);
        dev_put(dev);
  out_rtnl:
        rtnl_unlock();
@@ -1863,7 +1876,7 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
 
 static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info)
 {
-       struct cfg80211_registered_device *drv;
+       struct cfg80211_registered_device *rdev;
        int err;
        struct net_device *dev;
        u8 *mac_addr = NULL;
@@ -1873,7 +1886,7 @@ static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info)
 
        rtnl_lock();
 
-       err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
+       err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev);
        if (err)
                goto out_rtnl;
 
@@ -1884,15 +1897,15 @@ static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info)
                goto out;
        }
 
-       if (!drv->ops->del_station) {
+       if (!rdev->ops->del_station) {
                err = -EOPNOTSUPP;
                goto out;
        }
 
-       err = drv->ops->del_station(&drv->wiphy, dev, mac_addr);
+       err = rdev->ops->del_station(&rdev->wiphy, dev, mac_addr);
 
  out:
-       cfg80211_put_dev(drv);
+       cfg80211_unlock_rdev(rdev);
        dev_put(dev);
  out_rtnl:
        rtnl_unlock();
@@ -2023,7 +2036,7 @@ static int nl80211_dump_mpath(struct sk_buff *skb,
        cb->args[1] = path_idx;
        err = skb->len;
  out_err:
-       cfg80211_put_dev(dev);
+       cfg80211_unlock_rdev(dev);
  out_rtnl:
        rtnl_unlock();
 
@@ -2032,7 +2045,7 @@ static int nl80211_dump_mpath(struct sk_buff *skb,
 
 static int nl80211_get_mpath(struct sk_buff *skb, struct genl_info *info)
 {
-       struct cfg80211_registered_device *drv;
+       struct cfg80211_registered_device *rdev;
        int err;
        struct net_device *dev;
        struct mpath_info pinfo;
@@ -2049,11 +2062,11 @@ static int nl80211_get_mpath(struct sk_buff *skb, struct genl_info *info)
 
        rtnl_lock();
 
-       err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
+       err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev);
        if (err)
                goto out_rtnl;
 
-       if (!drv->ops->get_mpath) {
+       if (!rdev->ops->get_mpath) {
                err = -EOPNOTSUPP;
                goto out;
        }
@@ -2063,7 +2076,7 @@ static int nl80211_get_mpath(struct sk_buff *skb, struct genl_info *info)
                goto out;
        }
 
-       err = drv->ops->get_mpath(&drv->wiphy, dev, dst, next_hop, &pinfo);
+       err = rdev->ops->get_mpath(&rdev->wiphy, dev, dst, next_hop, &pinfo);
        if (err)
                goto out;
 
@@ -2075,13 +2088,13 @@ static int nl80211_get_mpath(struct sk_buff *skb, struct genl_info *info)
                                 dev, dst, next_hop, &pinfo) < 0)
                goto out_free;
 
-       err = genlmsg_unicast(msg, info->snd_pid);
+       err = genlmsg_reply(msg, info);
        goto out;
 
  out_free:
        nlmsg_free(msg);
  out:
-       cfg80211_put_dev(drv);
+       cfg80211_unlock_rdev(rdev);
        dev_put(dev);
  out_rtnl:
        rtnl_unlock();
@@ -2091,7 +2104,7 @@ static int nl80211_get_mpath(struct sk_buff *skb, struct genl_info *info)
 
 static int nl80211_set_mpath(struct sk_buff *skb, struct genl_info *info)
 {
-       struct cfg80211_registered_device *drv;
+       struct cfg80211_registered_device *rdev;
        int err;
        struct net_device *dev;
        u8 *dst = NULL;
@@ -2108,11 +2121,11 @@ static int nl80211_set_mpath(struct sk_buff *skb, struct genl_info *info)
 
        rtnl_lock();
 
-       err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
+       err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev);
        if (err)
                goto out_rtnl;
 
-       if (!drv->ops->change_mpath) {
+       if (!rdev->ops->change_mpath) {
                err = -EOPNOTSUPP;
                goto out;
        }
@@ -2127,10 +2140,10 @@ static int nl80211_set_mpath(struct sk_buff *skb, struct genl_info *info)
                goto out;
        }
 
-       err = drv->ops->change_mpath(&drv->wiphy, dev, dst, next_hop);
+       err = rdev->ops->change_mpath(&rdev->wiphy, dev, dst, next_hop);
 
  out:
-       cfg80211_put_dev(drv);
+       cfg80211_unlock_rdev(rdev);
        dev_put(dev);
  out_rtnl:
        rtnl_unlock();
@@ -2139,7 +2152,7 @@ static int nl80211_set_mpath(struct sk_buff *skb, struct genl_info *info)
 }
 static int nl80211_new_mpath(struct sk_buff *skb, struct genl_info *info)
 {
-       struct cfg80211_registered_device *drv;
+       struct cfg80211_registered_device *rdev;
        int err;
        struct net_device *dev;
        u8 *dst = NULL;
@@ -2156,11 +2169,11 @@ static int nl80211_new_mpath(struct sk_buff *skb, struct genl_info *info)
 
        rtnl_lock();
 
-       err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
+       err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev);
        if (err)
                goto out_rtnl;
 
-       if (!drv->ops->add_mpath) {
+       if (!rdev->ops->add_mpath) {
                err = -EOPNOTSUPP;
                goto out;
        }
@@ -2175,10 +2188,10 @@ static int nl80211_new_mpath(struct sk_buff *skb, struct genl_info *info)
                goto out;
        }
 
-       err = drv->ops->add_mpath(&drv->wiphy, dev, dst, next_hop);
+       err = rdev->ops->add_mpath(&rdev->wiphy, dev, dst, next_hop);
 
  out:
-       cfg80211_put_dev(drv);
+       cfg80211_unlock_rdev(rdev);
        dev_put(dev);
  out_rtnl:
        rtnl_unlock();
@@ -2188,7 +2201,7 @@ static int nl80211_new_mpath(struct sk_buff *skb, struct genl_info *info)
 
 static int nl80211_del_mpath(struct sk_buff *skb, struct genl_info *info)
 {
-       struct cfg80211_registered_device *drv;
+       struct cfg80211_registered_device *rdev;
        int err;
        struct net_device *dev;
        u8 *dst = NULL;
@@ -2198,19 +2211,19 @@ static int nl80211_del_mpath(struct sk_buff *skb, struct genl_info *info)
 
        rtnl_lock();
 
-       err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
+       err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev);
        if (err)
                goto out_rtnl;
 
-       if (!drv->ops->del_mpath) {
+       if (!rdev->ops->del_mpath) {
                err = -EOPNOTSUPP;
                goto out;
        }
 
-       err = drv->ops->del_mpath(&drv->wiphy, dev, dst);
+       err = rdev->ops->del_mpath(&rdev->wiphy, dev, dst);
 
  out:
-       cfg80211_put_dev(drv);
+       cfg80211_unlock_rdev(rdev);
        dev_put(dev);
  out_rtnl:
        rtnl_unlock();
@@ -2220,7 +2233,7 @@ static int nl80211_del_mpath(struct sk_buff *skb, struct genl_info *info)
 
 static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info)
 {
-       struct cfg80211_registered_device *drv;
+       struct cfg80211_registered_device *rdev;
        int err;
        struct net_device *dev;
        struct bss_parameters params;
@@ -2249,11 +2262,11 @@ static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info)
 
        rtnl_lock();
 
-       err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
+       err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev);
        if (err)
                goto out_rtnl;
 
-       if (!drv->ops->change_bss) {
+       if (!rdev->ops->change_bss) {
                err = -EOPNOTSUPP;
                goto out;
        }
@@ -2263,10 +2276,10 @@ static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info)
                goto out;
        }
 
-       err = drv->ops->change_bss(&drv->wiphy, dev, &params);
+       err = rdev->ops->change_bss(&rdev->wiphy, dev, &params);
 
  out:
-       cfg80211_put_dev(drv);
+       cfg80211_unlock_rdev(rdev);
        dev_put(dev);
  out_rtnl:
        rtnl_unlock();
@@ -2357,7 +2370,7 @@ static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info)
 static int nl80211_get_mesh_params(struct sk_buff *skb,
        struct genl_info *info)
 {
-       struct cfg80211_registered_device *drv;
+       struct cfg80211_registered_device *rdev;
        struct mesh_config cur_params;
        int err;
        struct net_device *dev;
@@ -2368,17 +2381,17 @@ static int nl80211_get_mesh_params(struct sk_buff *skb,
        rtnl_lock();
 
        /* Look up our device */
-       err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
+       err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev);
        if (err)
                goto out_rtnl;
 
-       if (!drv->ops->get_mesh_params) {
+       if (!rdev->ops->get_mesh_params) {
                err = -EOPNOTSUPP;
                goto out;
        }
 
        /* Get the mesh params */
-       err = drv->ops->get_mesh_params(&drv->wiphy, dev, &cur_params);
+       err = rdev->ops->get_mesh_params(&rdev->wiphy, dev, &cur_params);
        if (err)
                goto out;
 
@@ -2424,7 +2437,7 @@ static int nl80211_get_mesh_params(struct sk_buff *skb,
                        cur_params.dot11MeshHWMPnetDiameterTraversalTime);
        nla_nest_end(msg, pinfoattr);
        genlmsg_end(msg, hdr);
-       err = genlmsg_unicast(msg, info->snd_pid);
+       err = genlmsg_reply(msg, info);
        goto out;
 
  nla_put_failure:
@@ -2432,7 +2445,7 @@ static int nl80211_get_mesh_params(struct sk_buff *skb,
        err = -EMSGSIZE;
  out:
        /* Cleanup */
-       cfg80211_put_dev(drv);
+       cfg80211_unlock_rdev(rdev);
        dev_put(dev);
  out_rtnl:
        rtnl_unlock();
@@ -2470,7 +2483,7 @@ static int nl80211_set_mesh_params(struct sk_buff *skb, struct genl_info *info)
 {
        int err;
        u32 mask;
-       struct cfg80211_registered_device *drv;
+       struct cfg80211_registered_device *rdev;
        struct net_device *dev;
        struct mesh_config cfg;
        struct nlattr *tb[NL80211_MESHCONF_ATTR_MAX + 1];
@@ -2485,11 +2498,11 @@ static int nl80211_set_mesh_params(struct sk_buff *skb, struct genl_info *info)
 
        rtnl_lock();
 
-       err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
+       err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev);
        if (err)
                goto out_rtnl;
 
-       if (!drv->ops->set_mesh_params) {
+       if (!rdev->ops->set_mesh_params) {
                err = -EOPNOTSUPP;
                goto out;
        }
@@ -2534,11 +2547,11 @@ static int nl80211_set_mesh_params(struct sk_buff *skb, struct genl_info *info)
                        nla_get_u16);
 
        /* Apply changes */
-       err = drv->ops->set_mesh_params(&drv->wiphy, dev, &cfg, mask);
+       err = rdev->ops->set_mesh_params(&rdev->wiphy, dev, &cfg, mask);
 
  out:
        /* cleanup */
-       cfg80211_put_dev(drv);
+       cfg80211_unlock_rdev(rdev);
        dev_put(dev);
  out_rtnl:
        rtnl_unlock();
@@ -2612,7 +2625,7 @@ static int nl80211_get_reg(struct sk_buff *skb, struct genl_info *info)
        nla_nest_end(msg, nl_reg_rules);
 
        genlmsg_end(msg, hdr);
-       err = genlmsg_unicast(msg, info->snd_pid);
+       err = genlmsg_reply(msg, info);
        goto out;
 
 nla_put_failure:
@@ -2698,16 +2711,41 @@ static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info)
        return r;
 }
 
+static int validate_scan_freqs(struct nlattr *freqs)
+{
+       struct nlattr *attr1, *attr2;
+       int n_channels = 0, tmp1, tmp2;
+
+       nla_for_each_nested(attr1, freqs, tmp1) {
+               n_channels++;
+               /*
+                * Some hardware has a limited channel list for
+                * scanning, and it is pretty much nonsensical
+                * to scan for a channel twice, so disallow that
+                * and don't require drivers to check that the
+                * channel list they get isn't longer than what
+                * they can scan, as long as they can scan all
+                * the channels they registered at once.
+                */
+               nla_for_each_nested(attr2, freqs, tmp2)
+                       if (attr1 != attr2 &&
+                           nla_get_u32(attr1) == nla_get_u32(attr2))
+                               return 0;
+       }
+
+       return n_channels;
+}
+
 static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
 {
-       struct cfg80211_registered_device *drv;
+       struct cfg80211_registered_device *rdev;
        struct net_device *dev;
        struct cfg80211_scan_request *request;
        struct cfg80211_ssid *ssid;
        struct ieee80211_channel *channel;
        struct nlattr *attr;
        struct wiphy *wiphy;
-       int err, tmp, n_ssids = 0, n_channels = 0, i;
+       int err, tmp, n_ssids = 0, n_channels, i;
        enum ieee80211_band band;
        size_t ie_len;
 
@@ -2716,13 +2754,13 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
 
        rtnl_lock();
 
-       err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
+       err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev);
        if (err)
                goto out_rtnl;
 
-       wiphy = &drv->wiphy;
+       wiphy = &rdev->wiphy;
 
-       if (!drv->ops->scan) {
+       if (!rdev->ops->scan) {
                err = -EOPNOTSUPP;
                goto out;
        }
@@ -2732,19 +2770,21 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
                goto out;
        }
 
-       if (drv->scan_req) {
+       if (rdev->scan_req) {
                err = -EBUSY;
                goto out;
        }
 
        if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) {
-               nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_FREQUENCIES], tmp)
-                       n_channels++;
+               n_channels = validate_scan_freqs(
+                               info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]);
                if (!n_channels) {
                        err = -EINVAL;
                        goto out;
                }
        } else {
+               n_channels = 0;
+
                for (band = 0; band < IEEE80211_NUM_BANDS; band++)
                        if (wiphy->bands[band])
                                n_channels += wiphy->bands[band]->n_channels;
@@ -2837,18 +2877,21 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
        }
 
        request->ifidx = dev->ifindex;
-       request->wiphy = &drv->wiphy;
+       request->wiphy = &rdev->wiphy;
+
+       rdev->scan_req = request;
+       err = rdev->ops->scan(&rdev->wiphy, dev, request);
 
-       drv->scan_req = request;
-       err = drv->ops->scan(&drv->wiphy, dev, request);
+       if (!err)
+               nl80211_send_scan_start(rdev, dev);
 
  out_free:
        if (err) {
-               drv->scan_req = NULL;
+               rdev->scan_req = NULL;
                kfree(request);
        }
  out:
-       cfg80211_put_dev(drv);
+       cfg80211_unlock_rdev(rdev);
        dev_put(dev);
  out_rtnl:
        rtnl_unlock();
@@ -2965,7 +3008,7 @@ static int nl80211_dump_scan(struct sk_buff *skb,
 
        cb->args[1] = idx;
        err = skb->len;
-       cfg80211_put_dev(dev);
+       cfg80211_unlock_rdev(dev);
  out_put_netdev:
        dev_put(netdev);
 
@@ -2974,19 +3017,39 @@ static int nl80211_dump_scan(struct sk_buff *skb,
 
 static bool nl80211_valid_auth_type(enum nl80211_auth_type auth_type)
 {
-       return auth_type == NL80211_AUTHTYPE_OPEN_SYSTEM ||
-               auth_type == NL80211_AUTHTYPE_SHARED_KEY ||
-               auth_type == NL80211_AUTHTYPE_FT ||
-               auth_type == NL80211_AUTHTYPE_NETWORK_EAP;
+       return auth_type <= NL80211_AUTHTYPE_MAX;
+}
+
+static bool nl80211_valid_wpa_versions(u32 wpa_versions)
+{
+       return !(wpa_versions & ~(NL80211_WPA_VERSION_1 |
+                                 NL80211_WPA_VERSION_2));
+}
+
+static bool nl80211_valid_akm_suite(u32 akm)
+{
+       return akm == WLAN_AKM_SUITE_8021X ||
+               akm == WLAN_AKM_SUITE_PSK;
 }
 
+static bool nl80211_valid_cipher_suite(u32 cipher)
+{
+       return cipher == WLAN_CIPHER_SUITE_WEP40 ||
+               cipher == WLAN_CIPHER_SUITE_WEP104 ||
+               cipher == WLAN_CIPHER_SUITE_TKIP ||
+               cipher == WLAN_CIPHER_SUITE_CCMP ||
+               cipher == WLAN_CIPHER_SUITE_AES_CMAC;
+}
+
+
 static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
 {
-       struct cfg80211_registered_device *drv;
+       struct cfg80211_registered_device *rdev;
        struct net_device *dev;
-       struct cfg80211_auth_request req;
-       struct wiphy *wiphy;
-       int err;
+       struct ieee80211_channel *chan;
+       const u8 *bssid, *ssid, *ie = NULL;
+       int err, ssid_len, ie_len = 0;
+       enum nl80211_auth_type auth_type;
 
        if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
                return -EINVAL;
@@ -2997,13 +3060,19 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
        if (!info->attrs[NL80211_ATTR_AUTH_TYPE])
                return -EINVAL;
 
+       if (!info->attrs[NL80211_ATTR_SSID])
+               return -EINVAL;
+
+       if (!info->attrs[NL80211_ATTR_WIPHY_FREQ])
+               return -EINVAL;
+
        rtnl_lock();
 
-       err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
+       err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev);
        if (err)
                goto unlock_rtnl;
 
-       if (!drv->ops->auth) {
+       if (!rdev->ops->auth) {
                err = -EOPNOTSUPP;
                goto out;
        }
@@ -3018,69 +3087,127 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
                goto out;
        }
 
-       wiphy = &drv->wiphy;
-       memset(&req, 0, sizeof(req));
-
-       req.peer_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
-
-       if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
-               req.chan = ieee80211_get_channel(
-                       wiphy,
-                       nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]));
-               if (!req.chan) {
-                       err = -EINVAL;
-                       goto out;
-               }
+       bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
+       chan = ieee80211_get_channel(&rdev->wiphy,
+               nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]));
+       if (!chan || (chan->flags & IEEE80211_CHAN_DISABLED)) {
+               err = -EINVAL;
+               goto out;
        }
 
-       if (info->attrs[NL80211_ATTR_SSID]) {
-               req.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
-               req.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
-       }
+       ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
+       ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
 
        if (info->attrs[NL80211_ATTR_IE]) {
-               req.ie = nla_data(info->attrs[NL80211_ATTR_IE]);
-               req.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
+               ie = nla_data(info->attrs[NL80211_ATTR_IE]);
+               ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
        }
 
-       req.auth_type = nla_get_u32(info->attrs[NL80211_ATTR_AUTH_TYPE]);
-       if (!nl80211_valid_auth_type(req.auth_type)) {
+       auth_type = nla_get_u32(info->attrs[NL80211_ATTR_AUTH_TYPE]);
+       if (!nl80211_valid_auth_type(auth_type)) {
                err = -EINVAL;
                goto out;
        }
 
-       err = drv->ops->auth(&drv->wiphy, dev, &req);
+       err = cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid,
+                                ssid, ssid_len, ie, ie_len);
 
 out:
-       cfg80211_put_dev(drv);
+       cfg80211_unlock_rdev(rdev);
        dev_put(dev);
 unlock_rtnl:
        rtnl_unlock();
        return err;
 }
 
+static int nl80211_crypto_settings(struct genl_info *info,
+                                  struct cfg80211_crypto_settings *settings,
+                                  int cipher_limit)
+{
+       settings->control_port = info->attrs[NL80211_ATTR_CONTROL_PORT];
+
+       if (info->attrs[NL80211_ATTR_CIPHER_SUITES_PAIRWISE]) {
+               void *data;
+               int len, i;
+
+               data = nla_data(info->attrs[NL80211_ATTR_CIPHER_SUITES_PAIRWISE]);
+               len = nla_len(info->attrs[NL80211_ATTR_CIPHER_SUITES_PAIRWISE]);
+               settings->n_ciphers_pairwise = len / sizeof(u32);
+
+               if (len % sizeof(u32))
+                       return -EINVAL;
+
+               if (settings->n_ciphers_pairwise > cipher_limit)
+                       return -EINVAL;
+
+               memcpy(settings->ciphers_pairwise, data, len);
+
+               for (i = 0; i < settings->n_ciphers_pairwise; i++)
+                       if (!nl80211_valid_cipher_suite(
+                                       settings->ciphers_pairwise[i]))
+                               return -EINVAL;
+       }
+
+       if (info->attrs[NL80211_ATTR_CIPHER_SUITE_GROUP]) {
+               settings->cipher_group =
+                       nla_get_u32(info->attrs[NL80211_ATTR_CIPHER_SUITE_GROUP]);
+               if (!nl80211_valid_cipher_suite(settings->cipher_group))
+                       return -EINVAL;
+       }
+
+       if (info->attrs[NL80211_ATTR_WPA_VERSIONS]) {
+               settings->wpa_versions =
+                       nla_get_u32(info->attrs[NL80211_ATTR_WPA_VERSIONS]);
+               if (!nl80211_valid_wpa_versions(settings->wpa_versions))
+                       return -EINVAL;
+       }
+
+       if (info->attrs[NL80211_ATTR_AKM_SUITES]) {
+               void *data;
+               int len, i;
+
+               data = nla_data(info->attrs[NL80211_ATTR_AKM_SUITES]);
+               len = nla_len(info->attrs[NL80211_ATTR_AKM_SUITES]);
+               settings->n_akm_suites = len / sizeof(u32);
+
+               if (len % sizeof(u32))
+                       return -EINVAL;
+
+               memcpy(settings->akm_suites, data, len);
+
+               for (i = 0; i < settings->n_ciphers_pairwise; i++)
+                       if (!nl80211_valid_akm_suite(settings->akm_suites[i]))
+                               return -EINVAL;
+       }
+
+       return 0;
+}
+
 static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
 {
-       struct cfg80211_registered_device *drv;
+       struct cfg80211_registered_device *rdev;
        struct net_device *dev;
-       struct cfg80211_assoc_request req;
-       struct wiphy *wiphy;
-       int err;
+       struct cfg80211_crypto_settings crypto;
+       struct ieee80211_channel *chan;
+       const u8 *bssid, *ssid, *ie = NULL, *prev_bssid = NULL;
+       int err, ssid_len, ie_len = 0;
+       bool use_mfp = false;
 
        if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
                return -EINVAL;
 
        if (!info->attrs[NL80211_ATTR_MAC] ||
-           !info->attrs[NL80211_ATTR_SSID])
+           !info->attrs[NL80211_ATTR_SSID] ||
+           !info->attrs[NL80211_ATTR_WIPHY_FREQ])
                return -EINVAL;
 
        rtnl_lock();
 
-       err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
+       err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev);
        if (err)
                goto unlock_rtnl;
 
-       if (!drv->ops->assoc) {
+       if (!rdev->ops->assoc) {
                err = -EOPNOTSUPP;
                goto out;
        }
@@ -3095,46 +3222,45 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
                goto out;
        }
 
-       wiphy = &drv->wiphy;
-       memset(&req, 0, sizeof(req));
-
-       req.peer_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
+       bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
 
-       if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
-               req.chan = ieee80211_get_channel(
-                       wiphy,
-                       nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]));
-               if (!req.chan) {
-                       err = -EINVAL;
-                       goto out;
-               }
+       chan = ieee80211_get_channel(&rdev->wiphy,
+               nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]));
+       if (!chan || (chan->flags & IEEE80211_CHAN_DISABLED)) {
+               err = -EINVAL;
+               goto out;
        }
 
-       req.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
-       req.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
+       ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
+       ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
 
        if (info->attrs[NL80211_ATTR_IE]) {
-               req.ie = nla_data(info->attrs[NL80211_ATTR_IE]);
-               req.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
+               ie = nla_data(info->attrs[NL80211_ATTR_IE]);
+               ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
        }
 
        if (info->attrs[NL80211_ATTR_USE_MFP]) {
-               enum nl80211_mfp use_mfp =
+               enum nl80211_mfp mfp =
                        nla_get_u32(info->attrs[NL80211_ATTR_USE_MFP]);
-               if (use_mfp == NL80211_MFP_REQUIRED)
-                       req.use_mfp = true;
-               else if (use_mfp != NL80211_MFP_NO) {
+               if (mfp == NL80211_MFP_REQUIRED)
+                       use_mfp = true;
+               else if (mfp != NL80211_MFP_NO) {
                        err = -EINVAL;
                        goto out;
                }
        }
 
-       req.control_port = info->attrs[NL80211_ATTR_CONTROL_PORT];
+       if (info->attrs[NL80211_ATTR_PREV_BSSID])
+               prev_bssid = nla_data(info->attrs[NL80211_ATTR_PREV_BSSID]);
 
-       err = drv->ops->assoc(&drv->wiphy, dev, &req);
+       err = nl80211_crypto_settings(info, &crypto, 1);
+       if (!err)
+               err = cfg80211_mlme_assoc(rdev, dev, chan, bssid, prev_bssid,
+                                         ssid, ssid_len, ie, ie_len, use_mfp,
+                                         &crypto);
 
 out:
-       cfg80211_put_dev(drv);
+       cfg80211_unlock_rdev(rdev);
        dev_put(dev);
 unlock_rtnl:
        rtnl_unlock();
@@ -3143,11 +3269,11 @@ unlock_rtnl:
 
 static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info)
 {
-       struct cfg80211_registered_device *drv;
+       struct cfg80211_registered_device *rdev;
        struct net_device *dev;
-       struct cfg80211_deauth_request req;
-       struct wiphy *wiphy;
-       int err;
+       const u8 *ie = NULL, *bssid;
+       int err, ie_len = 0;
+       u16 reason_code;
 
        if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
                return -EINVAL;
@@ -3160,11 +3286,11 @@ static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info)
 
        rtnl_lock();
 
-       err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
+       err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev);
        if (err)
                goto unlock_rtnl;
 
-       if (!drv->ops->deauth) {
+       if (!rdev->ops->deauth) {
                err = -EOPNOTSUPP;
                goto out;
        }
@@ -3179,27 +3305,24 @@ static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info)
                goto out;
        }
 
-       wiphy = &drv->wiphy;
-       memset(&req, 0, sizeof(req));
-
-       req.peer_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
+       bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
 
-       req.reason_code = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]);
-       if (req.reason_code == 0) {
+       reason_code = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]);
+       if (reason_code == 0) {
                /* Reason Code 0 is reserved */
                err = -EINVAL;
                goto out;
        }
 
        if (info->attrs[NL80211_ATTR_IE]) {
-               req.ie = nla_data(info->attrs[NL80211_ATTR_IE]);
-               req.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
+               ie = nla_data(info->attrs[NL80211_ATTR_IE]);
+               ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
        }
 
-       err = drv->ops->deauth(&drv->wiphy, dev, &req);
+       err = cfg80211_mlme_deauth(rdev, dev, bssid, ie, ie_len, reason_code);
 
 out:
-       cfg80211_put_dev(drv);
+       cfg80211_unlock_rdev(rdev);
        dev_put(dev);
 unlock_rtnl:
        rtnl_unlock();
@@ -3208,11 +3331,11 @@ unlock_rtnl:
 
 static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info)
 {
-       struct cfg80211_registered_device *drv;
+       struct cfg80211_registered_device *rdev;
        struct net_device *dev;
-       struct cfg80211_disassoc_request req;
-       struct wiphy *wiphy;
-       int err;
+       const u8 *ie = NULL, *bssid;
+       int err, ie_len = 0;
+       u16 reason_code;
 
        if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
                return -EINVAL;
@@ -3225,11 +3348,11 @@ static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info)
 
        rtnl_lock();
 
-       err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
+       err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev);
        if (err)
                goto unlock_rtnl;
 
-       if (!drv->ops->disassoc) {
+       if (!rdev->ops->disassoc) {
                err = -EOPNOTSUPP;
                goto out;
        }
@@ -3244,27 +3367,24 @@ static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info)
                goto out;
        }
 
-       wiphy = &drv->wiphy;
-       memset(&req, 0, sizeof(req));
+       bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
 
-       req.peer_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
-
-       req.reason_code = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]);
-       if (req.reason_code == 0) {
+       reason_code = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]);
+       if (reason_code == 0) {
                /* Reason Code 0 is reserved */
                err = -EINVAL;
                goto out;
        }
 
        if (info->attrs[NL80211_ATTR_IE]) {
-               req.ie = nla_data(info->attrs[NL80211_ATTR_IE]);
-               req.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
+               ie = nla_data(info->attrs[NL80211_ATTR_IE]);
+               ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
        }
 
-       err = drv->ops->disassoc(&drv->wiphy, dev, &req);
+       err = cfg80211_mlme_disassoc(rdev, dev, bssid, ie, ie_len, reason_code);
 
 out:
-       cfg80211_put_dev(drv);
+       cfg80211_unlock_rdev(rdev);
        dev_put(dev);
 unlock_rtnl:
        rtnl_unlock();
@@ -3273,7 +3393,7 @@ unlock_rtnl:
 
 static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
 {
-       struct cfg80211_registered_device *drv;
+       struct cfg80211_registered_device *rdev;
        struct net_device *dev;
        struct cfg80211_ibss_params ibss;
        struct wiphy *wiphy;
@@ -3300,11 +3420,11 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
 
        rtnl_lock();
 
-       err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
+       err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev);
        if (err)
                goto unlock_rtnl;
 
-       if (!drv->ops->join_ibss) {
+       if (!rdev->ops->join_ibss) {
                err = -EOPNOTSUPP;
                goto out;
        }
@@ -3319,7 +3439,7 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
                goto out;
        }
 
-       wiphy = &drv->wiphy;
+       wiphy = &rdev->wiphy;
 
        if (info->attrs[NL80211_ATTR_MAC])
                ibss.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
@@ -3342,10 +3462,10 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
 
        ibss.channel_fixed = !!info->attrs[NL80211_ATTR_FREQ_FIXED];
 
-       err = cfg80211_join_ibss(drv, dev, &ibss);
+       err = cfg80211_join_ibss(rdev, dev, &ibss);
 
 out:
-       cfg80211_put_dev(drv);
+       cfg80211_unlock_rdev(rdev);
        dev_put(dev);
 unlock_rtnl:
        rtnl_unlock();
@@ -3354,17 +3474,17 @@ unlock_rtnl:
 
 static int nl80211_leave_ibss(struct sk_buff *skb, struct genl_info *info)
 {
-       struct cfg80211_registered_device *drv;
+       struct cfg80211_registered_device *rdev;
        struct net_device *dev;
        int err;
 
        rtnl_lock();
 
-       err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
+       err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev);
        if (err)
                goto unlock_rtnl;
 
-       if (!drv->ops->leave_ibss) {
+       if (!rdev->ops->leave_ibss) {
                err = -EOPNOTSUPP;
                goto out;
        }
@@ -3379,10 +3499,257 @@ static int nl80211_leave_ibss(struct sk_buff *skb, struct genl_info *info)
                goto out;
        }
 
-       err = cfg80211_leave_ibss(drv, dev, false);
+       err = cfg80211_leave_ibss(rdev, dev, false);
+
+out:
+       cfg80211_unlock_rdev(rdev);
+       dev_put(dev);
+unlock_rtnl:
+       rtnl_unlock();
+       return err;
+}
+
+#ifdef CONFIG_NL80211_TESTMODE
+static struct genl_multicast_group nl80211_testmode_mcgrp = {
+       .name = "testmode",
+};
+
+static int nl80211_testmode_do(struct sk_buff *skb, struct genl_info *info)
+{
+       struct cfg80211_registered_device *rdev;
+       int err;
+
+       if (!info->attrs[NL80211_ATTR_TESTDATA])
+               return -EINVAL;
+
+       rtnl_lock();
+
+       rdev = cfg80211_get_dev_from_info(info);
+       if (IS_ERR(rdev)) {
+               err = PTR_ERR(rdev);
+               goto unlock_rtnl;
+       }
+
+       err = -EOPNOTSUPP;
+       if (rdev->ops->testmode_cmd) {
+               rdev->testmode_info = info;
+               err = rdev->ops->testmode_cmd(&rdev->wiphy,
+                               nla_data(info->attrs[NL80211_ATTR_TESTDATA]),
+                               nla_len(info->attrs[NL80211_ATTR_TESTDATA]));
+               rdev->testmode_info = NULL;
+       }
+
+       cfg80211_unlock_rdev(rdev);
+
+ unlock_rtnl:
+       rtnl_unlock();
+       return err;
+}
+
+static struct sk_buff *
+__cfg80211_testmode_alloc_skb(struct cfg80211_registered_device *rdev,
+                             int approxlen, u32 pid, u32 seq, gfp_t gfp)
+{
+       struct sk_buff *skb;
+       void *hdr;
+       struct nlattr *data;
+
+       skb = nlmsg_new(approxlen + 100, gfp);
+       if (!skb)
+               return NULL;
+
+       hdr = nl80211hdr_put(skb, pid, seq, 0, NL80211_CMD_TESTMODE);
+       if (!hdr) {
+               kfree_skb(skb);
+               return NULL;
+       }
+
+       NLA_PUT_U32(skb, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
+       data = nla_nest_start(skb, NL80211_ATTR_TESTDATA);
+
+       ((void **)skb->cb)[0] = rdev;
+       ((void **)skb->cb)[1] = hdr;
+       ((void **)skb->cb)[2] = data;
+
+       return skb;
+
+ nla_put_failure:
+       kfree_skb(skb);
+       return NULL;
+}
+
+struct sk_buff *cfg80211_testmode_alloc_reply_skb(struct wiphy *wiphy,
+                                                 int approxlen)
+{
+       struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+
+       if (WARN_ON(!rdev->testmode_info))
+               return NULL;
+
+       return __cfg80211_testmode_alloc_skb(rdev, approxlen,
+                               rdev->testmode_info->snd_pid,
+                               rdev->testmode_info->snd_seq,
+                               GFP_KERNEL);
+}
+EXPORT_SYMBOL(cfg80211_testmode_alloc_reply_skb);
+
+int cfg80211_testmode_reply(struct sk_buff *skb)
+{
+       struct cfg80211_registered_device *rdev = ((void **)skb->cb)[0];
+       void *hdr = ((void **)skb->cb)[1];
+       struct nlattr *data = ((void **)skb->cb)[2];
+
+       if (WARN_ON(!rdev->testmode_info)) {
+               kfree_skb(skb);
+               return -EINVAL;
+       }
+
+       nla_nest_end(skb, data);
+       genlmsg_end(skb, hdr);
+       return genlmsg_reply(skb, rdev->testmode_info);
+}
+EXPORT_SYMBOL(cfg80211_testmode_reply);
+
+struct sk_buff *cfg80211_testmode_alloc_event_skb(struct wiphy *wiphy,
+                                                 int approxlen, gfp_t gfp)
+{
+       struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+
+       return __cfg80211_testmode_alloc_skb(rdev, approxlen, 0, 0, gfp);
+}
+EXPORT_SYMBOL(cfg80211_testmode_alloc_event_skb);
+
+void cfg80211_testmode_event(struct sk_buff *skb, gfp_t gfp)
+{
+       void *hdr = ((void **)skb->cb)[1];
+       struct nlattr *data = ((void **)skb->cb)[2];
+
+       nla_nest_end(skb, data);
+       genlmsg_end(skb, hdr);
+       genlmsg_multicast(skb, 0, nl80211_testmode_mcgrp.id, gfp);
+}
+EXPORT_SYMBOL(cfg80211_testmode_event);
+#endif
+
+static int nl80211_connect(struct sk_buff *skb, struct genl_info *info)
+{
+       struct cfg80211_registered_device *rdev;
+       struct net_device *dev;
+       struct cfg80211_connect_params connect;
+       struct wiphy *wiphy;
+       int err;
+
+       memset(&connect, 0, sizeof(connect));
+
+       if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
+               return -EINVAL;
+
+       if (!info->attrs[NL80211_ATTR_SSID] ||
+           !nla_len(info->attrs[NL80211_ATTR_SSID]))
+               return -EINVAL;
+
+       if (info->attrs[NL80211_ATTR_AUTH_TYPE]) {
+               connect.auth_type =
+                       nla_get_u32(info->attrs[NL80211_ATTR_AUTH_TYPE]);
+               if (!nl80211_valid_auth_type(connect.auth_type))
+                       return -EINVAL;
+       } else
+               connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC;
+
+       connect.privacy = info->attrs[NL80211_ATTR_PRIVACY];
+
+       err = nl80211_crypto_settings(info, &connect.crypto,
+                                     NL80211_MAX_NR_CIPHER_SUITES);
+       if (err)
+               return err;
+       rtnl_lock();
+
+       err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev);
+       if (err)
+               goto unlock_rtnl;
+
+       if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) {
+               err = -EOPNOTSUPP;
+               goto out;
+       }
+
+       if (!netif_running(dev)) {
+               err = -ENETDOWN;
+               goto out;
+       }
+
+       wiphy = &rdev->wiphy;
+
+       connect.bssid = NULL;
+       connect.channel = NULL;
+       connect.auth_type = NL80211_AUTHTYPE_OPEN_SYSTEM;
+
+       if (info->attrs[NL80211_ATTR_MAC])
+               connect.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
+       connect.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
+       connect.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
+
+       if (info->attrs[NL80211_ATTR_IE]) {
+               connect.ie = nla_data(info->attrs[NL80211_ATTR_IE]);
+               connect.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
+       }
+
+       if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
+               connect.channel =
+                       ieee80211_get_channel(wiphy,
+                           nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]));
+               if (!connect.channel ||
+                   connect.channel->flags & IEEE80211_CHAN_DISABLED) {
+                       err = -EINVAL;
+                       goto out;
+               }
+       }
+
+       err = cfg80211_connect(rdev, dev, &connect);
 
 out:
-       cfg80211_put_dev(drv);
+       cfg80211_unlock_rdev(rdev);
+       dev_put(dev);
+unlock_rtnl:
+       rtnl_unlock();
+       return err;
+}
+
+static int nl80211_disconnect(struct sk_buff *skb, struct genl_info *info)
+{
+       struct cfg80211_registered_device *rdev;
+       struct net_device *dev;
+       int err;
+       u16 reason;
+
+       if (!info->attrs[NL80211_ATTR_REASON_CODE])
+               reason = WLAN_REASON_DEAUTH_LEAVING;
+       else
+               reason = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]);
+
+       if (reason == 0)
+               return -EINVAL;
+
+       rtnl_lock();
+
+       err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev);
+       if (err)
+               goto unlock_rtnl;
+
+       if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) {
+               err = -EOPNOTSUPP;
+               goto out;
+       }
+
+       if (!netif_running(dev)) {
+               err = -ENETDOWN;
+               goto out;
+       }
+
+       err = cfg80211_disconnect(rdev, dev, reason, true);
+
+out:
+       cfg80211_unlock_rdev(rdev);
        dev_put(dev);
 unlock_rtnl:
        rtnl_unlock();
@@ -3602,6 +3969,26 @@ static struct genl_ops nl80211_ops[] = {
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
        },
+#ifdef CONFIG_NL80211_TESTMODE
+       {
+               .cmd = NL80211_CMD_TESTMODE,
+               .doit = nl80211_testmode_do,
+               .policy = nl80211_policy,
+               .flags = GENL_ADMIN_PERM,
+       },
+#endif
+       {
+               .cmd = NL80211_CMD_CONNECT,
+               .doit = nl80211_connect,
+               .policy = nl80211_policy,
+               .flags = GENL_ADMIN_PERM,
+       },
+       {
+               .cmd = NL80211_CMD_DISCONNECT,
+               .doit = nl80211_disconnect,
+               .policy = nl80211_policy,
+               .flags = GENL_ADMIN_PERM,
+       },
 };
 static struct genl_multicast_group nl80211_mlme_mcgrp = {
        .name = "mlme",
@@ -3643,6 +4030,8 @@ static int nl80211_add_scan_req(struct sk_buff *msg,
        struct nlattr *nest;
        int i;
 
+       ASSERT_RDEV_LOCK(rdev);
+
        if (WARN_ON(!req))
                return 0;
 
@@ -3668,11 +4057,11 @@ static int nl80211_add_scan_req(struct sk_buff *msg,
        return -ENOBUFS;
 }
 
-static int nl80211_send_scan_donemsg(struct sk_buff *msg,
-                                    struct cfg80211_registered_device *rdev,
-                                    struct net_device *netdev,
-                                    u32 pid, u32 seq, int flags,
-                                    u32 cmd)
+static int nl80211_send_scan_msg(struct sk_buff *msg,
+                                struct cfg80211_registered_device *rdev,
+                                struct net_device *netdev,
+                                u32 pid, u32 seq, int flags,
+                                u32 cmd)
 {
        void *hdr;
 
@@ -3693,6 +4082,24 @@ static int nl80211_send_scan_donemsg(struct sk_buff *msg,
        return -EMSGSIZE;
 }
 
+void nl80211_send_scan_start(struct cfg80211_registered_device *rdev,
+                            struct net_device *netdev)
+{
+       struct sk_buff *msg;
+
+       msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
+       if (!msg)
+               return;
+
+       if (nl80211_send_scan_msg(msg, rdev, netdev, 0, 0, 0,
+                                 NL80211_CMD_TRIGGER_SCAN) < 0) {
+               nlmsg_free(msg);
+               return;
+       }
+
+       genlmsg_multicast(msg, 0, nl80211_scan_mcgrp.id, GFP_KERNEL);
+}
+
 void nl80211_send_scan_done(struct cfg80211_registered_device *rdev,
                            struct net_device *netdev)
 {
@@ -3702,8 +4109,8 @@ void nl80211_send_scan_done(struct cfg80211_registered_device *rdev,
        if (!msg)
                return;
 
-       if (nl80211_send_scan_donemsg(msg, rdev, netdev, 0, 0, 0,
-                                     NL80211_CMD_NEW_SCAN_RESULTS) < 0) {
+       if (nl80211_send_scan_msg(msg, rdev, netdev, 0, 0, 0,
+                                 NL80211_CMD_NEW_SCAN_RESULTS) < 0) {
                nlmsg_free(msg);
                return;
        }
@@ -3720,8 +4127,8 @@ void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev,
        if (!msg)
                return;
 
-       if (nl80211_send_scan_donemsg(msg, rdev, netdev, 0, 0, 0,
-                                     NL80211_CMD_SCAN_ABORTED) < 0) {
+       if (nl80211_send_scan_msg(msg, rdev, netdev, 0, 0, 0,
+                                 NL80211_CMD_SCAN_ABORTED) < 0) {
                nlmsg_free(msg);
                return;
        }
@@ -3787,12 +4194,12 @@ nla_put_failure:
 static void nl80211_send_mlme_event(struct cfg80211_registered_device *rdev,
                                    struct net_device *netdev,
                                    const u8 *buf, size_t len,
-                                   enum nl80211_commands cmd)
+                                   enum nl80211_commands cmd, gfp_t gfp)
 {
        struct sk_buff *msg;
        void *hdr;
 
-       msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
+       msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
        if (!msg)
                return;
 
@@ -3811,7 +4218,7 @@ static void nl80211_send_mlme_event(struct cfg80211_registered_device *rdev,
                return;
        }
 
-       genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, GFP_ATOMIC);
+       genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, gfp);
        return;
 
  nla_put_failure:
@@ -3820,42 +4227,45 @@ static void nl80211_send_mlme_event(struct cfg80211_registered_device *rdev,
 }
 
 void nl80211_send_rx_auth(struct cfg80211_registered_device *rdev,
-                         struct net_device *netdev, const u8 *buf, size_t len)
+                         struct net_device *netdev, const u8 *buf,
+                         size_t len, gfp_t gfp)
 {
        nl80211_send_mlme_event(rdev, netdev, buf, len,
-                               NL80211_CMD_AUTHENTICATE);
+                               NL80211_CMD_AUTHENTICATE, gfp);
 }
 
 void nl80211_send_rx_assoc(struct cfg80211_registered_device *rdev,
                           struct net_device *netdev, const u8 *buf,
-                          size_t len)
+                          size_t len, gfp_t gfp)
 {
-       nl80211_send_mlme_event(rdev, netdev, buf, len, NL80211_CMD_ASSOCIATE);
+       nl80211_send_mlme_event(rdev, netdev, buf, len,
+                               NL80211_CMD_ASSOCIATE, gfp);
 }
 
 void nl80211_send_deauth(struct cfg80211_registered_device *rdev,
-                        struct net_device *netdev, const u8 *buf, size_t len)
+                        struct net_device *netdev, const u8 *buf,
+                        size_t len, gfp_t gfp)
 {
        nl80211_send_mlme_event(rdev, netdev, buf, len,
-                               NL80211_CMD_DEAUTHENTICATE);
+                               NL80211_CMD_DEAUTHENTICATE, gfp);
 }
 
 void nl80211_send_disassoc(struct cfg80211_registered_device *rdev,
                           struct net_device *netdev, const u8 *buf,
-                          size_t len)
+                          size_t len, gfp_t gfp)
 {
        nl80211_send_mlme_event(rdev, netdev, buf, len,
-                               NL80211_CMD_DISASSOCIATE);
+                               NL80211_CMD_DISASSOCIATE, gfp);
 }
 
 static void nl80211_send_mlme_timeout(struct cfg80211_registered_device *rdev,
                                      struct net_device *netdev, int cmd,
-                                     const u8 *addr)
+                                     const u8 *addr, gfp_t gfp)
 {
        struct sk_buff *msg;
        void *hdr;
 
-       msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
+       msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
        if (!msg)
                return;
 
@@ -3875,7 +4285,7 @@ static void nl80211_send_mlme_timeout(struct cfg80211_registered_device *rdev,
                return;
        }
 
-       genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, GFP_ATOMIC);
+       genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, gfp);
        return;
 
  nla_put_failure:
@@ -3884,16 +4294,142 @@ static void nl80211_send_mlme_timeout(struct cfg80211_registered_device *rdev,
 }
 
 void nl80211_send_auth_timeout(struct cfg80211_registered_device *rdev,
-                              struct net_device *netdev, const u8 *addr)
+                              struct net_device *netdev, const u8 *addr,
+                              gfp_t gfp)
 {
        nl80211_send_mlme_timeout(rdev, netdev, NL80211_CMD_AUTHENTICATE,
-                                 addr);
+                                 addr, gfp);
 }
 
 void nl80211_send_assoc_timeout(struct cfg80211_registered_device *rdev,
-                               struct net_device *netdev, const u8 *addr)
+                               struct net_device *netdev, const u8 *addr,
+                               gfp_t gfp)
 {
-       nl80211_send_mlme_timeout(rdev, netdev, NL80211_CMD_ASSOCIATE, addr);
+       nl80211_send_mlme_timeout(rdev, netdev, NL80211_CMD_ASSOCIATE,
+                                 addr, gfp);
+}
+
+void nl80211_send_connect_result(struct cfg80211_registered_device *rdev,
+                                struct net_device *netdev, const u8 *bssid,
+                                const u8 *req_ie, size_t req_ie_len,
+                                const u8 *resp_ie, size_t resp_ie_len,
+                                u16 status, gfp_t gfp)
+{
+       struct sk_buff *msg;
+       void *hdr;
+
+       msg = nlmsg_new(NLMSG_GOODSIZE, gfp);
+       if (!msg)
+               return;
+
+       hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_CONNECT);
+       if (!hdr) {
+               nlmsg_free(msg);
+               return;
+       }
+
+       NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
+       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex);
+       if (bssid)
+               NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid);
+       NLA_PUT_U16(msg, NL80211_ATTR_STATUS_CODE, status);
+       if (req_ie)
+               NLA_PUT(msg, NL80211_ATTR_REQ_IE, req_ie_len, req_ie);
+       if (resp_ie)
+               NLA_PUT(msg, NL80211_ATTR_RESP_IE, resp_ie_len, resp_ie);
+
+       if (genlmsg_end(msg, hdr) < 0) {
+               nlmsg_free(msg);
+               return;
+       }
+
+       genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, gfp);
+       return;
+
+ nla_put_failure:
+       genlmsg_cancel(msg, hdr);
+       nlmsg_free(msg);
+
+}
+
+void nl80211_send_roamed(struct cfg80211_registered_device *rdev,
+                        struct net_device *netdev, const u8 *bssid,
+                        const u8 *req_ie, size_t req_ie_len,
+                        const u8 *resp_ie, size_t resp_ie_len, gfp_t gfp)
+{
+       struct sk_buff *msg;
+       void *hdr;
+
+       msg = nlmsg_new(NLMSG_GOODSIZE, gfp);
+       if (!msg)
+               return;
+
+       hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_ROAM);
+       if (!hdr) {
+               nlmsg_free(msg);
+               return;
+       }
+
+       NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
+       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex);
+       NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid);
+       if (req_ie)
+               NLA_PUT(msg, NL80211_ATTR_REQ_IE, req_ie_len, req_ie);
+       if (resp_ie)
+               NLA_PUT(msg, NL80211_ATTR_RESP_IE, resp_ie_len, resp_ie);
+
+       if (genlmsg_end(msg, hdr) < 0) {
+               nlmsg_free(msg);
+               return;
+       }
+
+       genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, gfp);
+       return;
+
+ nla_put_failure:
+       genlmsg_cancel(msg, hdr);
+       nlmsg_free(msg);
+
+}
+
+void nl80211_send_disconnected(struct cfg80211_registered_device *rdev,
+                              struct net_device *netdev, u16 reason,
+                              const u8 *ie, size_t ie_len, bool from_ap)
+{
+       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_DISCONNECT);
+       if (!hdr) {
+               nlmsg_free(msg);
+               return;
+       }
+
+       NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
+       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex);
+       if (from_ap && reason)
+               NLA_PUT_U16(msg, NL80211_ATTR_REASON_CODE, reason);
+       if (from_ap)
+               NLA_PUT_FLAG(msg, NL80211_ATTR_DISCONNECTED_BY_AP);
+       if (ie)
+               NLA_PUT(msg, NL80211_ATTR_IE, ie_len, ie);
+
+       if (genlmsg_end(msg, hdr) < 0) {
+               nlmsg_free(msg);
+               return;
+       }
+
+       genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, GFP_KERNEL);
+       return;
+
+ nla_put_failure:
+       genlmsg_cancel(msg, hdr);
+       nlmsg_free(msg);
+
 }
 
 void nl80211_send_ibss_bssid(struct cfg80211_registered_device *rdev,
@@ -3933,12 +4469,12 @@ void nl80211_send_ibss_bssid(struct cfg80211_registered_device *rdev,
 void nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev,
                                 struct net_device *netdev, const u8 *addr,
                                 enum nl80211_key_type key_type, int key_id,
-                                const u8 *tsc)
+                                const u8 *tsc, gfp_t gfp)
 {
        struct sk_buff *msg;
        void *hdr;
 
-       msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
+       msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
        if (!msg)
                return;
 
@@ -3962,7 +4498,7 @@ void nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev,
                return;
        }
 
-       genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, GFP_ATOMIC);
+       genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, gfp);
        return;
 
  nla_put_failure:
@@ -4051,6 +4587,12 @@ int nl80211_init(void)
        if (err)
                goto err_out;
 
+#ifdef CONFIG_NL80211_TESTMODE
+       err = genl_register_mc_group(&nl80211_fam, &nl80211_testmode_mcgrp);
+       if (err)
+               goto err_out;
+#endif
+
        return 0;
  err_out:
        genl_unregister_family(&nl80211_fam);
index 5c12ad1..44cc2a7 100644 (file)
@@ -3,39 +3,54 @@
 
 #include "core.h"
 
-extern int nl80211_init(void);
-extern void nl80211_exit(void);
-extern void nl80211_notify_dev_rename(struct cfg80211_registered_device *rdev);
-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);
-extern void nl80211_send_rx_auth(struct cfg80211_registered_device *rdev,
-                                struct net_device *netdev,
-                                const u8 *buf, size_t len);
-extern void nl80211_send_rx_assoc(struct cfg80211_registered_device *rdev,
-                                 struct net_device *netdev,
-                                 const u8 *buf, size_t len);
-extern void nl80211_send_deauth(struct cfg80211_registered_device *rdev,
+int nl80211_init(void);
+void nl80211_exit(void);
+void nl80211_notify_dev_rename(struct cfg80211_registered_device *rdev);
+void nl80211_send_scan_start(struct cfg80211_registered_device *rdev,
+                            struct net_device *netdev);
+void nl80211_send_scan_done(struct cfg80211_registered_device *rdev,
+                           struct net_device *netdev);
+void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev,
+                              struct net_device *netdev);
+void nl80211_send_reg_change_event(struct regulatory_request *request);
+void nl80211_send_rx_auth(struct cfg80211_registered_device *rdev,
+                         struct net_device *netdev,
+                         const u8 *buf, size_t len, gfp_t gfp);
+void nl80211_send_rx_assoc(struct cfg80211_registered_device *rdev,
+                          struct net_device *netdev,
+                          const u8 *buf, size_t len, gfp_t gfp);
+void nl80211_send_deauth(struct cfg80211_registered_device *rdev,
+                        struct net_device *netdev,
+                        const u8 *buf, size_t len, gfp_t gfp);
+void nl80211_send_disassoc(struct cfg80211_registered_device *rdev,
+                          struct net_device *netdev,
+                          const u8 *buf, size_t len, gfp_t gfp);
+void nl80211_send_auth_timeout(struct cfg80211_registered_device *rdev,
+                              struct net_device *netdev,
+                              const u8 *addr, gfp_t gfp);
+void nl80211_send_assoc_timeout(struct cfg80211_registered_device *rdev,
                                struct net_device *netdev,
-                               const u8 *buf, size_t len);
-extern void nl80211_send_disassoc(struct cfg80211_registered_device *rdev,
-                                 struct net_device *netdev,
-                                 const u8 *buf, size_t len);
-extern void nl80211_send_auth_timeout(struct cfg80211_registered_device *rdev,
-                                     struct net_device *netdev,
-                                     const u8 *addr);
-extern void nl80211_send_assoc_timeout(struct cfg80211_registered_device *rdev,
-                                      struct net_device *netdev,
-                                      const u8 *addr);
-extern void
+                               const u8 *addr, gfp_t gfp);
+void nl80211_send_connect_result(struct cfg80211_registered_device *rdev,
+                                struct net_device *netdev, const u8 *bssid,
+                                const u8 *req_ie, size_t req_ie_len,
+                                const u8 *resp_ie, size_t resp_ie_len,
+                                u16 status, gfp_t gfp);
+void nl80211_send_roamed(struct cfg80211_registered_device *rdev,
+                        struct net_device *netdev, const u8 *bssid,
+                        const u8 *req_ie, size_t req_ie_len,
+                        const u8 *resp_ie, size_t resp_ie_len, gfp_t gfp);
+void nl80211_send_disconnected(struct cfg80211_registered_device *rdev,
+                              struct net_device *netdev, u16 reason,
+                              const u8 *ie, size_t ie_len, bool from_ap);
+
+void
 nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev,
                            struct net_device *netdev, const u8 *addr,
                            enum nl80211_key_type key_type,
-                           int key_id, const u8 *tsc);
+                           int key_id, const u8 *tsc, gfp_t gfp);
 
-extern void
+void
 nl80211_send_beacon_hint_event(struct wiphy *wiphy,
                               struct ieee80211_channel *channel_before,
                               struct ieee80211_channel *channel_after);
index 5e14371..2b4a6c6 100644 (file)
@@ -1061,10 +1061,10 @@ static bool ignore_reg_update(struct wiphy *wiphy,
 
 static void update_all_wiphy_regulatory(enum nl80211_reg_initiator initiator)
 {
-       struct cfg80211_registered_device *drv;
+       struct cfg80211_registered_device *rdev;
 
-       list_for_each_entry(drv, &cfg80211_drv_list, list)
-               wiphy_update_regulatory(&drv->wiphy, initiator);
+       list_for_each_entry(rdev, &cfg80211_rdev_list, list)
+               wiphy_update_regulatory(&rdev->wiphy, initiator);
 }
 
 static void handle_reg_beacon(struct wiphy *wiphy,
@@ -1614,7 +1614,7 @@ static void reg_process_pending_hints(void)
 /* 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 cfg80211_registered_device *rdev;
        struct reg_beacon *pending_beacon, *tmp;
 
        mutex_lock(&cfg80211_mutex);
@@ -1633,8 +1633,8 @@ static void reg_process_pending_beacon_hints(void)
                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);
+               list_for_each_entry(rdev, &cfg80211_rdev_list, list)
+                       wiphy_update_new_beacon(&rdev->wiphy, pending_beacon);
 
                /* Remembers the beacon hint for new wiphys or reg changes */
                list_add_tail(&pending_beacon->list, &reg_beacon_list);
@@ -1814,23 +1814,23 @@ void regulatory_hint_11d(struct wiphy *wiphy,
        if (likely(last_request->initiator ==
            NL80211_REGDOM_SET_BY_COUNTRY_IE &&
            wiphy_idx_valid(last_request->wiphy_idx))) {
-               struct cfg80211_registered_device *drv_last_ie;
+               struct cfg80211_registered_device *rdev_last_ie;
 
-               drv_last_ie =
-                       cfg80211_drv_by_wiphy_idx(last_request->wiphy_idx);
+               rdev_last_ie =
+                       cfg80211_rdev_by_wiphy_idx(last_request->wiphy_idx);
 
                /*
                 * Lets keep this simple -- we trust the first AP
                 * after we intersect with CRDA
                 */
-               if (likely(&drv_last_ie->wiphy == wiphy)) {
+               if (likely(&rdev_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,
+                       if (likely(alpha2_equal(rdev_last_ie->country_ie_alpha2,
                                  alpha2) &&
-                                 env == drv_last_ie->env)) {
+                                 env == rdev_last_ie->env)) {
                                goto out;
                        }
                        /*
@@ -1846,9 +1846,9 @@ void regulatory_hint_11d(struct wiphy *wiphy,
                         * 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,
+                       if (likely(alpha2_equal(rdev_last_ie->country_ie_alpha2,
                                  alpha2) &&
-                                 env == drv_last_ie->env)) {
+                                 env == rdev_last_ie->env)) {
                                goto out;
                        }
                        /* We could potentially intersect though */
@@ -1995,14 +1995,14 @@ static void print_regdomain(const struct ieee80211_regdomain *rd)
 
                if (last_request->initiator ==
                    NL80211_REGDOM_SET_BY_COUNTRY_IE) {
-                       struct cfg80211_registered_device *drv;
-                       drv = cfg80211_drv_by_wiphy_idx(
+                       struct cfg80211_registered_device *rdev;
+                       rdev = cfg80211_rdev_by_wiphy_idx(
                                last_request->wiphy_idx);
-                       if (drv) {
+                       if (rdev) {
                                printk(KERN_INFO "cfg80211: Current regulatory "
                                        "domain updated by AP to: %c%c\n",
-                                       drv->country_ie_alpha2[0],
-                                       drv->country_ie_alpha2[1]);
+                                       rdev->country_ie_alpha2[0],
+                                       rdev->country_ie_alpha2[1]);
                        } else
                                printk(KERN_INFO "cfg80211: Current regulatory "
                                        "domain intersected: \n");
@@ -2063,7 +2063,7 @@ static inline void reg_country_ie_process_debug(
 static int __set_regdom(const struct ieee80211_regdomain *rd)
 {
        const struct ieee80211_regdomain *intersected_rd = NULL;
-       struct cfg80211_registered_device *drv = NULL;
+       struct cfg80211_registered_device *rdev = NULL;
        struct wiphy *request_wiphy;
        /* Some basic sanity checks first */
 
@@ -2202,11 +2202,11 @@ static int __set_regdom(const struct ieee80211_regdomain *rd)
        if (!intersected_rd)
                return -EINVAL;
 
-       drv = wiphy_to_dev(request_wiphy);
+       rdev = wiphy_to_dev(request_wiphy);
 
-       drv->country_ie_alpha2[0] = rd->alpha2[0];
-       drv->country_ie_alpha2[1] = rd->alpha2[1];
-       drv->env = last_request->country_ie_env;
+       rdev->country_ie_alpha2[0] = rd->alpha2[0];
+       rdev->country_ie_alpha2[1] = rd->alpha2[1];
+       rdev->env = last_request->country_ie_env;
 
        BUG_ON(intersected_rd == rd);
 
index 9271118..decc59f 100644 (file)
 
 #define IEEE80211_SCAN_RESULT_EXPIRE   (10 * HZ)
 
-void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted)
+void __cfg80211_scan_done(struct work_struct *wk)
 {
+       struct cfg80211_registered_device *rdev;
+       struct cfg80211_scan_request *request;
        struct net_device *dev;
 #ifdef CONFIG_WIRELESS_EXT
        union iwreq_data wrqu;
 #endif
 
+       rdev = container_of(wk, struct cfg80211_registered_device,
+                           scan_done_wk);
+
+       mutex_lock(&rdev->mtx);
+       request = rdev->scan_req;
+
        dev = dev_get_by_index(&init_net, request->ifidx);
        if (!dev)
                goto out;
 
-       WARN_ON(request != wiphy_to_dev(request->wiphy)->scan_req);
+       /*
+        * This must be before sending the other events!
+        * Otherwise, wpa_supplicant gets completely confused with
+        * wext events.
+        */
+       cfg80211_sme_scan_done(dev);
 
-       if (aborted)
+       if (request->aborted)
                nl80211_send_scan_aborted(wiphy_to_dev(request->wiphy), dev);
        else
                nl80211_send_scan_done(wiphy_to_dev(request->wiphy), dev);
 
 #ifdef CONFIG_WIRELESS_EXT
-       if (!aborted) {
+       if (!request->aborted) {
                memset(&wrqu, 0, sizeof(wrqu));
 
                wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL);
@@ -46,9 +59,25 @@ void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted)
        dev_put(dev);
 
  out:
+       cfg80211_unlock_rdev(rdev);
        wiphy_to_dev(request->wiphy)->scan_req = NULL;
        kfree(request);
 }
+
+void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted)
+{
+       struct net_device *dev = dev_get_by_index(&init_net, request->ifidx);
+       if (WARN_ON(!dev)) {
+               kfree(request);
+               return;
+       }
+
+       WARN_ON(request != wiphy_to_dev(request->wiphy)->scan_req);
+
+       request->aborted = aborted;
+       schedule_work(&wiphy_to_dev(request->wiphy)->scan_done_wk);
+       dev_put(dev);
+}
 EXPORT_SYMBOL(cfg80211_scan_done);
 
 static void bss_release(struct kref *ref)
@@ -62,6 +91,8 @@ static void bss_release(struct kref *ref)
        if (bss->ies_allocated)
                kfree(bss->pub.information_elements);
 
+       BUG_ON(atomic_read(&bss->hold));
+
        kfree(bss);
 }
 
@@ -84,8 +115,9 @@ void cfg80211_bss_expire(struct cfg80211_registered_device *dev)
        bool expired = false;
 
        list_for_each_entry_safe(bss, tmp, &dev->bss_list, list) {
-               if (bss->hold ||
-                   !time_after(jiffies, bss->ts + IEEE80211_SCAN_RESULT_EXPIRE))
+               if (atomic_read(&bss->hold))
+                       continue;
+               if (!time_after(jiffies, bss->ts + IEEE80211_SCAN_RESULT_EXPIRE))
                        continue;
                list_del(&bss->list);
                rb_erase(&bss->rbn, &dev->bss_tree);
@@ -545,30 +577,6 @@ void cfg80211_unlink_bss(struct wiphy *wiphy, struct cfg80211_bss *pub)
 }
 EXPORT_SYMBOL(cfg80211_unlink_bss);
 
-void cfg80211_hold_bss(struct cfg80211_bss *pub)
-{
-       struct cfg80211_internal_bss *bss;
-
-       if (!pub)
-               return;
-
-       bss = container_of(pub, struct cfg80211_internal_bss, pub);
-       bss->hold = true;
-}
-EXPORT_SYMBOL(cfg80211_hold_bss);
-
-void cfg80211_unhold_bss(struct cfg80211_bss *pub)
-{
-       struct cfg80211_internal_bss *bss;
-
-       if (!pub)
-               return;
-
-       bss = container_of(pub, struct cfg80211_internal_bss, pub);
-       bss->hold = false;
-}
-EXPORT_SYMBOL(cfg80211_unhold_bss);
-
 #ifdef CONFIG_WIRELESS_EXT
 int cfg80211_wext_siwscan(struct net_device *dev,
                          struct iw_request_info *info,
@@ -646,9 +654,10 @@ int cfg80211_wext_siwscan(struct net_device *dev,
        if (err) {
                rdev->scan_req = NULL;
                kfree(creq);
-       }
+       } else
+               nl80211_send_scan_start(rdev, dev);
  out:
-       cfg80211_put_dev(rdev);
+       cfg80211_unlock_rdev(rdev);
        return err;
 }
 EXPORT_SYMBOL_GPL(cfg80211_wext_siwscan);
@@ -957,7 +966,7 @@ int cfg80211_wext_giwscan(struct net_device *dev,
        }
 
  out:
-       cfg80211_put_dev(rdev);
+       cfg80211_unlock_rdev(rdev);
        return res;
 }
 EXPORT_SYMBOL_GPL(cfg80211_wext_giwscan);
diff --git a/net/wireless/sme.c b/net/wireless/sme.c
new file mode 100644 (file)
index 0000000..df9173f
--- /dev/null
@@ -0,0 +1,792 @@
+/*
+ * SME code for cfg80211's connect emulation.
+ *
+ * Copyright 2009      Johannes Berg <johannes@sipsolutions.net>
+ * Copyright (C) 2009   Intel Corporation. All rights reserved.
+ */
+
+#include <linux/etherdevice.h>
+#include <linux/if_arp.h>
+#include <linux/workqueue.h>
+#include <net/cfg80211.h>
+#include <net/rtnetlink.h>
+#include "nl80211.h"
+
+struct cfg80211_conn {
+       struct cfg80211_connect_params params;
+       /* these are sub-states of the _CONNECTING sme_state */
+       enum {
+               CFG80211_CONN_IDLE,
+               CFG80211_CONN_SCANNING,
+               CFG80211_CONN_SCAN_AGAIN,
+               CFG80211_CONN_AUTHENTICATE_NEXT,
+               CFG80211_CONN_AUTHENTICATING,
+               CFG80211_CONN_ASSOCIATE_NEXT,
+               CFG80211_CONN_ASSOCIATING,
+       } state;
+       u8 bssid[ETH_ALEN];
+       u8 *ie;
+       size_t ie_len;
+       bool auto_auth;
+};
+
+
+static int cfg80211_conn_scan(struct wireless_dev *wdev)
+{
+       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+       struct cfg80211_scan_request *request;
+       int n_channels, err;
+
+       ASSERT_RTNL();
+       ASSERT_RDEV_LOCK(rdev);
+       ASSERT_WDEV_LOCK(wdev);
+
+       if (rdev->scan_req)
+               return -EBUSY;
+
+       if (wdev->conn->params.channel) {
+               n_channels = 1;
+       } else {
+               enum ieee80211_band band;
+               n_channels = 0;
+
+               for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
+                       if (!wdev->wiphy->bands[band])
+                               continue;
+                       n_channels += wdev->wiphy->bands[band]->n_channels;
+               }
+       }
+       request = kzalloc(sizeof(*request) + sizeof(request->ssids[0]) +
+                         sizeof(request->channels[0]) * n_channels,
+                         GFP_KERNEL);
+       if (!request)
+               return -ENOMEM;
+
+       request->channels = (void *)((char *)request + sizeof(*request));
+       if (wdev->conn->params.channel)
+               request->channels[0] = wdev->conn->params.channel;
+       else {
+               int i = 0, j;
+               enum ieee80211_band band;
+
+               for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
+                       if (!wdev->wiphy->bands[band])
+                               continue;
+                       for (j = 0; j < wdev->wiphy->bands[band]->n_channels;
+                            i++, j++)
+                               request->channels[i] =
+                                       &wdev->wiphy->bands[band]->channels[j];
+               }
+       }
+       request->n_channels = n_channels;
+       request->ssids = (void *)(request->channels + n_channels);
+       request->n_ssids = 1;
+
+       memcpy(request->ssids[0].ssid, wdev->conn->params.ssid,
+               wdev->conn->params.ssid_len);
+       request->ssids[0].ssid_len = wdev->conn->params.ssid_len;
+
+       request->ifidx = wdev->netdev->ifindex;
+       request->wiphy = &rdev->wiphy;
+
+       rdev->scan_req = request;
+
+       err = rdev->ops->scan(wdev->wiphy, wdev->netdev, request);
+       if (!err) {
+               wdev->conn->state = CFG80211_CONN_SCANNING;
+               nl80211_send_scan_start(rdev, wdev->netdev);
+       } else {
+               rdev->scan_req = NULL;
+               kfree(request);
+       }
+       return err;
+}
+
+static int cfg80211_conn_do_work(struct wireless_dev *wdev)
+{
+       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+       struct cfg80211_connect_params *params;
+       int err;
+
+       ASSERT_WDEV_LOCK(wdev);
+
+       if (!wdev->conn)
+               return 0;
+
+       params = &wdev->conn->params;
+
+       switch (wdev->conn->state) {
+       case CFG80211_CONN_SCAN_AGAIN:
+               return cfg80211_conn_scan(wdev);
+       case CFG80211_CONN_AUTHENTICATE_NEXT:
+               BUG_ON(!rdev->ops->auth);
+               wdev->conn->state = CFG80211_CONN_AUTHENTICATING;
+               return __cfg80211_mlme_auth(rdev, wdev->netdev,
+                                           params->channel, params->auth_type,
+                                           params->bssid,
+                                           params->ssid, params->ssid_len,
+                                           NULL, 0);
+       case CFG80211_CONN_ASSOCIATE_NEXT:
+               BUG_ON(!rdev->ops->assoc);
+               wdev->conn->state = CFG80211_CONN_ASSOCIATING;
+               /*
+                * We could, later, implement roaming here and then actually
+                * set prev_bssid to non-NULL. But then we need to be aware
+                * that some APs don't like that -- so we'd need to retry
+                * the association.
+                */
+               err = __cfg80211_mlme_assoc(rdev, wdev->netdev,
+                                           params->channel, params->bssid,
+                                           NULL,
+                                           params->ssid, params->ssid_len,
+                                           params->ie, params->ie_len,
+                                           false, &params->crypto);
+               if (err)
+                       __cfg80211_mlme_deauth(rdev, wdev->netdev, params->bssid,
+                                              NULL, 0,
+                                              WLAN_REASON_DEAUTH_LEAVING);
+               return err;
+       default:
+               return 0;
+       }
+}
+
+void cfg80211_conn_work(struct work_struct *work)
+{
+       struct cfg80211_registered_device *rdev =
+               container_of(work, struct cfg80211_registered_device, conn_work);
+       struct wireless_dev *wdev;
+
+       rtnl_lock();
+       cfg80211_lock_rdev(rdev);
+       mutex_lock(&rdev->devlist_mtx);
+
+       list_for_each_entry(wdev, &rdev->netdev_list, list) {
+               wdev_lock(wdev);
+               if (!netif_running(wdev->netdev)) {
+                       wdev_unlock(wdev);
+                       continue;
+               }
+               if (wdev->sme_state != CFG80211_SME_CONNECTING) {
+                       wdev_unlock(wdev);
+                       continue;
+               }
+               if (cfg80211_conn_do_work(wdev))
+                       __cfg80211_connect_result(
+                                       wdev->netdev,
+                                       wdev->conn->params.bssid,
+                                       NULL, 0, NULL, 0,
+                                       WLAN_STATUS_UNSPECIFIED_FAILURE,
+                                       false);
+               wdev_unlock(wdev);
+       }
+
+       mutex_unlock(&rdev->devlist_mtx);
+       cfg80211_unlock_rdev(rdev);
+       rtnl_unlock();
+}
+
+static bool cfg80211_get_conn_bss(struct wireless_dev *wdev)
+{
+       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+       struct cfg80211_bss *bss;
+       u16 capa = WLAN_CAPABILITY_ESS;
+
+       ASSERT_WDEV_LOCK(wdev);
+
+       if (wdev->conn->params.privacy)
+               capa |= WLAN_CAPABILITY_PRIVACY;
+
+       bss = cfg80211_get_bss(wdev->wiphy, NULL, wdev->conn->params.bssid,
+                              wdev->conn->params.ssid,
+                              wdev->conn->params.ssid_len,
+                              WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_PRIVACY,
+                              capa);
+       if (!bss)
+               return false;
+
+       memcpy(wdev->conn->bssid, bss->bssid, ETH_ALEN);
+       wdev->conn->params.bssid = wdev->conn->bssid;
+       wdev->conn->params.channel = bss->channel;
+       wdev->conn->state = CFG80211_CONN_AUTHENTICATE_NEXT;
+       schedule_work(&rdev->conn_work);
+
+       cfg80211_put_bss(bss);
+       return true;
+}
+
+static void __cfg80211_sme_scan_done(struct net_device *dev)
+{
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+
+       ASSERT_WDEV_LOCK(wdev);
+
+       if (wdev->sme_state != CFG80211_SME_CONNECTING)
+               return;
+
+       if (WARN_ON(!wdev->conn))
+               return;
+
+       if (wdev->conn->state != CFG80211_CONN_SCANNING &&
+           wdev->conn->state != CFG80211_CONN_SCAN_AGAIN)
+               return;
+
+       if (!cfg80211_get_conn_bss(wdev)) {
+               /* not found */
+               if (wdev->conn->state == CFG80211_CONN_SCAN_AGAIN)
+                       schedule_work(&rdev->conn_work);
+               else
+                       __cfg80211_connect_result(
+                                       wdev->netdev,
+                                       wdev->conn->params.bssid,
+                                       NULL, 0, NULL, 0,
+                                       WLAN_STATUS_UNSPECIFIED_FAILURE,
+                                       false);
+       }
+}
+
+void cfg80211_sme_scan_done(struct net_device *dev)
+{
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+
+       wdev_lock(wdev);
+       __cfg80211_sme_scan_done(dev);
+       wdev_unlock(wdev);
+}
+
+void cfg80211_sme_rx_auth(struct net_device *dev,
+                         const u8 *buf, size_t len)
+{
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+       struct wiphy *wiphy = wdev->wiphy;
+       struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+       struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
+       u16 status_code = le16_to_cpu(mgmt->u.auth.status_code);
+
+       ASSERT_WDEV_LOCK(wdev);
+
+       /* should only RX auth frames when connecting */
+       if (wdev->sme_state != CFG80211_SME_CONNECTING)
+               return;
+
+       if (WARN_ON(!wdev->conn))
+               return;
+
+       if (status_code == WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG &&
+           wdev->conn->auto_auth &&
+           wdev->conn->params.auth_type != NL80211_AUTHTYPE_NETWORK_EAP) {
+               /* select automatically between only open, shared, leap */
+               switch (wdev->conn->params.auth_type) {
+               case NL80211_AUTHTYPE_OPEN_SYSTEM:
+                       wdev->conn->params.auth_type =
+                               NL80211_AUTHTYPE_SHARED_KEY;
+                       break;
+               case NL80211_AUTHTYPE_SHARED_KEY:
+                       wdev->conn->params.auth_type =
+                               NL80211_AUTHTYPE_NETWORK_EAP;
+                       break;
+               default:
+                       /* huh? */
+                       wdev->conn->params.auth_type =
+                               NL80211_AUTHTYPE_OPEN_SYSTEM;
+                       break;
+               }
+               wdev->conn->state = CFG80211_CONN_AUTHENTICATE_NEXT;
+               schedule_work(&rdev->conn_work);
+       } else if (status_code != WLAN_STATUS_SUCCESS) {
+               wdev->sme_state = CFG80211_SME_IDLE;
+               kfree(wdev->conn);
+               wdev->conn = NULL;
+       } else if (wdev->sme_state == CFG80211_SME_CONNECTING &&
+                wdev->conn->state == CFG80211_CONN_AUTHENTICATING) {
+               wdev->conn->state = CFG80211_CONN_ASSOCIATE_NEXT;
+               schedule_work(&rdev->conn_work);
+       }
+}
+
+void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
+                              const u8 *req_ie, size_t req_ie_len,
+                              const u8 *resp_ie, size_t resp_ie_len,
+                              u16 status, bool wextev)
+{
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+       struct cfg80211_bss *bss;
+#ifdef CONFIG_WIRELESS_EXT
+       union iwreq_data wrqu;
+#endif
+
+       ASSERT_WDEV_LOCK(wdev);
+
+       if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION))
+               return;
+
+       if (wdev->sme_state == CFG80211_SME_CONNECTED)
+               nl80211_send_roamed(wiphy_to_dev(wdev->wiphy), dev,
+                                   bssid, req_ie, req_ie_len,
+                                   resp_ie, resp_ie_len, GFP_KERNEL);
+       else
+               nl80211_send_connect_result(wiphy_to_dev(wdev->wiphy), dev,
+                                           bssid, req_ie, req_ie_len,
+                                           resp_ie, resp_ie_len,
+                                           status, GFP_KERNEL);
+
+#ifdef CONFIG_WIRELESS_EXT
+       if (wextev) {
+               if (req_ie && status == WLAN_STATUS_SUCCESS) {
+                       memset(&wrqu, 0, sizeof(wrqu));
+                       wrqu.data.length = req_ie_len;
+                       wireless_send_event(dev, IWEVASSOCRESPIE, &wrqu, req_ie);
+               }
+
+               if (resp_ie && status == WLAN_STATUS_SUCCESS) {
+                       memset(&wrqu, 0, sizeof(wrqu));
+                       wrqu.data.length = resp_ie_len;
+                       wireless_send_event(dev, IWEVASSOCRESPIE, &wrqu, resp_ie);
+               }
+
+               memset(&wrqu, 0, sizeof(wrqu));
+               wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+               if (bssid && status == WLAN_STATUS_SUCCESS)
+                       memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN);
+               wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
+       }
+#endif
+
+       if (status == WLAN_STATUS_SUCCESS &&
+           wdev->sme_state == CFG80211_SME_IDLE) {
+               wdev->sme_state = CFG80211_SME_CONNECTED;
+               return;
+       }
+
+       if (wdev->sme_state != CFG80211_SME_CONNECTING)
+               return;
+
+       if (wdev->current_bss) {
+               cfg80211_unhold_bss(wdev->current_bss);
+               cfg80211_put_bss(&wdev->current_bss->pub);
+               wdev->current_bss = NULL;
+       }
+
+       if (wdev->conn)
+               wdev->conn->state = CFG80211_CONN_IDLE;
+
+       if (status == WLAN_STATUS_SUCCESS) {
+               bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid,
+                                      wdev->ssid, wdev->ssid_len,
+                                      WLAN_CAPABILITY_ESS,
+                                      WLAN_CAPABILITY_ESS);
+
+               if (WARN_ON(!bss))
+                       return;
+
+               cfg80211_hold_bss(bss_from_pub(bss));
+               wdev->current_bss = bss_from_pub(bss);
+
+               wdev->sme_state = CFG80211_SME_CONNECTED;
+       } else {
+               wdev->sme_state = CFG80211_SME_IDLE;
+               kfree(wdev->conn);
+               wdev->conn = NULL;
+       }
+}
+
+void cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
+                            const u8 *req_ie, size_t req_ie_len,
+                            const u8 *resp_ie, size_t resp_ie_len,
+                            u16 status, gfp_t gfp)
+{
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+       struct cfg80211_event *ev;
+       unsigned long flags;
+
+       ev = kzalloc(sizeof(*ev) + req_ie_len + resp_ie_len, gfp);
+       if (!ev)
+               return;
+
+       ev->type = EVENT_CONNECT_RESULT;
+       memcpy(ev->cr.bssid, bssid, ETH_ALEN);
+       ev->cr.req_ie = ((u8 *)ev) + sizeof(*ev);
+       ev->cr.req_ie_len = req_ie_len;
+       memcpy((void *)ev->cr.req_ie, req_ie, req_ie_len);
+       ev->cr.resp_ie = ((u8 *)ev) + sizeof(*ev) + req_ie_len;
+       ev->cr.resp_ie_len = resp_ie_len;
+       memcpy((void *)ev->cr.resp_ie, resp_ie, resp_ie_len);
+       ev->cr.status = status;
+
+       spin_lock_irqsave(&wdev->event_lock, flags);
+       list_add_tail(&ev->list, &wdev->event_list);
+       spin_unlock_irqrestore(&wdev->event_lock, flags);
+       schedule_work(&rdev->event_work);
+}
+EXPORT_SYMBOL(cfg80211_connect_result);
+
+void __cfg80211_roamed(struct wireless_dev *wdev, const u8 *bssid,
+                      const u8 *req_ie, size_t req_ie_len,
+                      const u8 *resp_ie, size_t resp_ie_len)
+{
+       struct cfg80211_bss *bss;
+#ifdef CONFIG_WIRELESS_EXT
+       union iwreq_data wrqu;
+#endif
+
+       ASSERT_WDEV_LOCK(wdev);
+
+       if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION))
+               return;
+
+       if (WARN_ON(wdev->sme_state != CFG80211_SME_CONNECTED))
+               return;
+
+       /* internal error -- how did we get to CONNECTED w/o BSS? */
+       if (WARN_ON(!wdev->current_bss)) {
+               return;
+       }
+
+       cfg80211_unhold_bss(wdev->current_bss);
+       cfg80211_put_bss(&wdev->current_bss->pub);
+       wdev->current_bss = NULL;
+
+       bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid,
+                              wdev->ssid, wdev->ssid_len,
+                              WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
+
+       if (WARN_ON(!bss))
+               return;
+
+       cfg80211_hold_bss(bss_from_pub(bss));
+       wdev->current_bss = bss_from_pub(bss);
+
+       nl80211_send_roamed(wiphy_to_dev(wdev->wiphy), wdev->netdev, bssid,
+                           req_ie, req_ie_len, resp_ie, resp_ie_len,
+                           GFP_KERNEL);
+
+#ifdef CONFIG_WIRELESS_EXT
+       if (req_ie) {
+               memset(&wrqu, 0, sizeof(wrqu));
+               wrqu.data.length = req_ie_len;
+               wireless_send_event(wdev->netdev, IWEVASSOCRESPIE,
+                                   &wrqu, req_ie);
+       }
+
+       if (resp_ie) {
+               memset(&wrqu, 0, sizeof(wrqu));
+               wrqu.data.length = resp_ie_len;
+               wireless_send_event(wdev->netdev, IWEVASSOCRESPIE,
+                                   &wrqu, resp_ie);
+       }
+
+       memset(&wrqu, 0, sizeof(wrqu));
+       wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+       memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN);
+       wireless_send_event(wdev->netdev, SIOCGIWAP, &wrqu, NULL);
+#endif
+}
+
+void cfg80211_roamed(struct net_device *dev, const u8 *bssid,
+                    const u8 *req_ie, size_t req_ie_len,
+                    const u8 *resp_ie, size_t resp_ie_len, gfp_t gfp)
+{
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+       struct cfg80211_event *ev;
+       unsigned long flags;
+
+       ev = kzalloc(sizeof(*ev) + req_ie_len + resp_ie_len, gfp);
+       if (!ev)
+               return;
+
+       ev->type = EVENT_ROAMED;
+       memcpy(ev->rm.bssid, bssid, ETH_ALEN);
+       ev->rm.req_ie = ((u8 *)ev) + sizeof(*ev);
+       ev->rm.req_ie_len = req_ie_len;
+       memcpy((void *)ev->rm.req_ie, req_ie, req_ie_len);
+       ev->rm.resp_ie = ((u8 *)ev) + sizeof(*ev) + req_ie_len;
+       ev->rm.resp_ie_len = resp_ie_len;
+       memcpy((void *)ev->rm.resp_ie, resp_ie, resp_ie_len);
+
+       spin_lock_irqsave(&wdev->event_lock, flags);
+       list_add_tail(&ev->list, &wdev->event_list);
+       spin_unlock_irqrestore(&wdev->event_lock, flags);
+       schedule_work(&rdev->event_work);
+}
+EXPORT_SYMBOL(cfg80211_roamed);
+
+void __cfg80211_disconnected(struct net_device *dev, const u8 *ie,
+                            size_t ie_len, u16 reason, bool from_ap)
+{
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+#ifdef CONFIG_WIRELESS_EXT
+       union iwreq_data wrqu;
+#endif
+
+       ASSERT_WDEV_LOCK(wdev);
+
+       if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION))
+               return;
+
+       if (WARN_ON(wdev->sme_state != CFG80211_SME_CONNECTED))
+               return;
+
+       if (wdev->current_bss) {
+               cfg80211_unhold_bss(wdev->current_bss);
+               cfg80211_put_bss(&wdev->current_bss->pub);
+       }
+
+       wdev->current_bss = NULL;
+       wdev->sme_state = CFG80211_SME_IDLE;
+
+       if (wdev->conn) {
+               kfree(wdev->conn->ie);
+               wdev->conn->ie = NULL;
+               kfree(wdev->conn);
+               wdev->conn = NULL;
+       }
+
+       nl80211_send_disconnected(wiphy_to_dev(wdev->wiphy), dev,
+                                 reason, ie, ie_len, from_ap);
+
+#ifdef CONFIG_WIRELESS_EXT
+       memset(&wrqu, 0, sizeof(wrqu));
+       wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+       wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
+#endif
+}
+
+void cfg80211_disconnected(struct net_device *dev, u16 reason,
+                          u8 *ie, size_t ie_len, gfp_t gfp)
+{
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+       struct cfg80211_event *ev;
+       unsigned long flags;
+
+       ev = kzalloc(sizeof(*ev) + ie_len, gfp);
+       if (!ev)
+               return;
+
+       ev->type = EVENT_DISCONNECTED;
+       ev->dc.ie = ((u8 *)ev) + sizeof(*ev);
+       ev->dc.ie_len = ie_len;
+       memcpy((void *)ev->dc.ie, ie, ie_len);
+       ev->dc.reason = reason;
+
+       spin_lock_irqsave(&wdev->event_lock, flags);
+       list_add_tail(&ev->list, &wdev->event_list);
+       spin_unlock_irqrestore(&wdev->event_lock, flags);
+       schedule_work(&rdev->event_work);
+}
+EXPORT_SYMBOL(cfg80211_disconnected);
+
+int __cfg80211_connect(struct cfg80211_registered_device *rdev,
+                      struct net_device *dev,
+                      struct cfg80211_connect_params *connect)
+{
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+       int err;
+
+       ASSERT_WDEV_LOCK(wdev);
+
+       if (wdev->sme_state != CFG80211_SME_IDLE)
+               return -EALREADY;
+
+       if (!rdev->ops->connect) {
+               if (!rdev->ops->auth || !rdev->ops->assoc)
+                       return -EOPNOTSUPP;
+
+               if (WARN_ON(wdev->conn))
+                       return -EINPROGRESS;
+
+               wdev->conn = kzalloc(sizeof(*wdev->conn), GFP_KERNEL);
+               if (!wdev->conn)
+                       return -ENOMEM;
+
+               /*
+                * Copy all parameters, and treat explicitly IEs, BSSID, SSID.
+                */
+               memcpy(&wdev->conn->params, connect, sizeof(*connect));
+               if (connect->bssid) {
+                       wdev->conn->params.bssid = wdev->conn->bssid;
+                       memcpy(wdev->conn->bssid, connect->bssid, ETH_ALEN);
+               }
+
+               if (connect->ie) {
+                       wdev->conn->ie = kmemdup(connect->ie, connect->ie_len,
+                                               GFP_KERNEL);
+                       wdev->conn->params.ie = wdev->conn->ie;
+                       if (!wdev->conn->ie) {
+                               kfree(wdev->conn);
+                               wdev->conn = NULL;
+                               return -ENOMEM;
+                       }
+               }
+
+               if (connect->auth_type == NL80211_AUTHTYPE_AUTOMATIC) {
+                       wdev->conn->auto_auth = true;
+                       /* start with open system ... should mostly work */
+                       wdev->conn->params.auth_type =
+                               NL80211_AUTHTYPE_OPEN_SYSTEM;
+               } else {
+                       wdev->conn->auto_auth = false;
+               }
+
+               memcpy(wdev->ssid, connect->ssid, connect->ssid_len);
+               wdev->ssid_len = connect->ssid_len;
+               wdev->conn->params.ssid = wdev->ssid;
+               wdev->conn->params.ssid_len = connect->ssid_len;
+
+               /* don't care about result -- but fill bssid & channel */
+               if (!wdev->conn->params.bssid || !wdev->conn->params.channel)
+                       cfg80211_get_conn_bss(wdev);
+
+               wdev->sme_state = CFG80211_SME_CONNECTING;
+
+               /* we're good if we have both BSSID and channel */
+               if (wdev->conn->params.bssid && wdev->conn->params.channel) {
+                       wdev->conn->state = CFG80211_CONN_AUTHENTICATE_NEXT;
+                       err = cfg80211_conn_do_work(wdev);
+               } else {
+                       /* otherwise we'll need to scan for the AP first */
+                       err = cfg80211_conn_scan(wdev);
+                       /*
+                        * If we can't scan right now, then we need to scan again
+                        * after the current scan finished, since the parameters
+                        * changed (unless we find a good AP anyway).
+                        */
+                       if (err == -EBUSY) {
+                               err = 0;
+                               wdev->conn->state = CFG80211_CONN_SCAN_AGAIN;
+                       }
+               }
+               if (err) {
+                       kfree(wdev->conn);
+                       wdev->conn = NULL;
+                       wdev->sme_state = CFG80211_SME_IDLE;
+               }
+
+               return err;
+       } else {
+               wdev->sme_state = CFG80211_SME_CONNECTING;
+               err = rdev->ops->connect(&rdev->wiphy, dev, connect);
+               if (err) {
+                       wdev->sme_state = CFG80211_SME_IDLE;
+                       return err;
+               }
+
+               memcpy(wdev->ssid, connect->ssid, connect->ssid_len);
+               wdev->ssid_len = connect->ssid_len;
+
+               return 0;
+       }
+}
+
+int cfg80211_connect(struct cfg80211_registered_device *rdev,
+                    struct net_device *dev,
+                    struct cfg80211_connect_params *connect)
+{
+       int err;
+
+       wdev_lock(dev->ieee80211_ptr);
+       err = __cfg80211_connect(rdev, dev, connect);
+       wdev_unlock(dev->ieee80211_ptr);
+
+       return err;
+}
+
+int __cfg80211_disconnect(struct cfg80211_registered_device *rdev,
+                         struct net_device *dev, u16 reason, bool wextev)
+{
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+       int err;
+
+       ASSERT_WDEV_LOCK(wdev);
+
+       if (wdev->sme_state == CFG80211_SME_IDLE)
+               return -EINVAL;
+
+       if (!rdev->ops->disconnect) {
+               if (!rdev->ops->deauth)
+                       return -EOPNOTSUPP;
+
+               /* was it connected by userspace SME? */
+               if (!wdev->conn) {
+                       cfg80211_mlme_down(rdev, dev);
+                       return 0;
+               }
+
+               if (wdev->sme_state == CFG80211_SME_CONNECTING &&
+                   (wdev->conn->state == CFG80211_CONN_SCANNING ||
+                    wdev->conn->state == CFG80211_CONN_SCAN_AGAIN)) {
+                       wdev->sme_state = CFG80211_SME_IDLE;
+                       kfree(wdev->conn);
+                       wdev->conn = NULL;
+                       return 0;
+               }
+
+               /* wdev->conn->params.bssid must be set if > SCANNING */
+               err = __cfg80211_mlme_deauth(rdev, dev,
+                                            wdev->conn->params.bssid,
+                                            NULL, 0, reason);
+               if (err)
+                       return err;
+       } else {
+               err = rdev->ops->disconnect(&rdev->wiphy, dev, reason);
+               if (err)
+                       return err;
+       }
+
+       if (wdev->sme_state == CFG80211_SME_CONNECTED)
+               __cfg80211_disconnected(dev, NULL, 0, 0, false);
+       else if (wdev->sme_state == CFG80211_SME_CONNECTING)
+               __cfg80211_connect_result(dev, NULL, NULL, 0, NULL, 0,
+                                         WLAN_STATUS_UNSPECIFIED_FAILURE,
+                                         wextev);
+
+       return 0;
+}
+
+int cfg80211_disconnect(struct cfg80211_registered_device *rdev,
+                       struct net_device *dev,
+                       u16 reason, bool wextev)
+{
+       int err;
+
+       wdev_lock(dev->ieee80211_ptr);
+       err = __cfg80211_disconnect(rdev, dev, reason, wextev);
+       wdev_unlock(dev->ieee80211_ptr);
+
+       return err;
+}
+
+void cfg80211_sme_disassoc(struct net_device *dev, int idx)
+{
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+       u8 bssid[ETH_ALEN];
+
+       ASSERT_WDEV_LOCK(wdev);
+
+       if (!wdev->conn)
+               return;
+
+       if (wdev->conn->state == CFG80211_CONN_IDLE)
+               return;
+
+       /*
+        * Ok, so the association was made by this SME -- we don't
+        * want it any more so deauthenticate too.
+        */
+
+       if (!wdev->auth_bsses[idx])
+               return;
+
+       memcpy(bssid, wdev->auth_bsses[idx]->pub.bssid, ETH_ALEN);
+       if (cfg80211_mlme_deauth(rdev, dev, bssid,
+                                NULL, 0, WLAN_REASON_DEAUTH_LEAVING)) {
+               /* whatever -- assume gone anyway */
+               cfg80211_unhold_bss(wdev->auth_bsses[idx]);
+               cfg80211_put_bss(&wdev->auth_bsses[idx]->pub);
+               wdev->auth_bsses[idx] = NULL;
+       }
+}
index 2555069..28f8f96 100644 (file)
@@ -502,3 +502,24 @@ unsigned int cfg80211_classify8021d(struct sk_buff *skb)
        return dscp >> 5;
 }
 EXPORT_SYMBOL(cfg80211_classify8021d);
+
+const u8 *ieee80211_bss_get_ie(struct cfg80211_bss *bss, u8 ie)
+{
+       u8 *end, *pos;
+
+       pos = bss->information_elements;
+       if (pos == NULL)
+               return NULL;
+       end = pos + bss->len_information_elements;
+
+       while (pos + 1 < end) {
+               if (pos + 2 + pos[1] > end)
+                       break;
+               if (pos[0] == ie)
+                       return pos;
+               pos += 2 + pos[1];
+       }
+
+       return NULL;
+}
+EXPORT_SYMBOL(ieee80211_bss_get_ie);
index d030c53..9d101d5 100644 (file)
@@ -103,7 +103,7 @@ int cfg80211_wext_siwmode(struct net_device *dev, struct iw_request_info *info,
 
        memset(&vifparams, 0, sizeof(vifparams));
 
-       ret = rdev->ops->change_virtual_intf(wdev->wiphy, dev->ifindex, type,
+       ret = rdev->ops->change_virtual_intf(wdev->wiphy, dev, type,
                                             NULL, &vifparams);
        WARN_ON(!ret && wdev->iftype != type);
 
@@ -154,7 +154,7 @@ int cfg80211_wext_giwrange(struct net_device *dev,
        struct wireless_dev *wdev = dev->ieee80211_ptr;
        struct iw_range *range = (struct iw_range *) extra;
        enum ieee80211_band band;
-       int c = 0;
+       int i, c = 0;
 
        if (!wdev)
                return -EOPNOTSUPP;
@@ -173,9 +173,6 @@ int cfg80211_wext_giwrange(struct net_device *dev,
        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;
@@ -204,11 +201,31 @@ int cfg80211_wext_giwrange(struct net_device *dev,
        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 (i = 0; i < wdev->wiphy->n_cipher_suites; i++) {
+               switch (wdev->wiphy->cipher_suites[i]) {
+               case WLAN_CIPHER_SUITE_TKIP:
+                       range->enc_capa |= (IW_ENC_CAPA_CIPHER_TKIP |
+                                           IW_ENC_CAPA_WPA);
+                       break;
+
+               case WLAN_CIPHER_SUITE_CCMP:
+                       range->enc_capa |= (IW_ENC_CAPA_CIPHER_CCMP |
+                                           IW_ENC_CAPA_WPA2);
+                       break;
+
+               case WLAN_CIPHER_SUITE_WEP40:
+                       range->encoding_size[range->num_encoding_sizes++] =
+                               WLAN_KEY_LEN_WEP40;
+                       break;
+
+               case WLAN_CIPHER_SUITE_WEP104:
+                       range->encoding_size[range->num_encoding_sizes++] =
+                               WLAN_KEY_LEN_WEP104;
+                       break;
+               }
+       }
 
        for (band = 0; band < IEEE80211_NUM_BANDS; band ++) {
-               int i;
                struct ieee80211_supported_band *sband;
 
                sband = wdev->wiphy->bands[band];
@@ -236,56 +253,13 @@ int cfg80211_wext_giwrange(struct net_device *dev,
        IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWAP);
        IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWSCAN);
 
-       range->scan_capa |= IW_SCAN_CAPA_ESSID;
+       if (wdev->wiphy->max_scan_ssids > 0)
+               range->scan_capa |= IW_SCAN_CAPA_ESSID;
 
        return 0;
 }
 EXPORT_SYMBOL_GPL(cfg80211_wext_giwrange);
 
-int cfg80211_wext_siwmlme(struct net_device *dev,
-                         struct iw_request_info *info,
-                         struct iw_point *data, char *extra)
-{
-       struct wireless_dev *wdev = dev->ieee80211_ptr;
-       struct iw_mlme *mlme = (struct iw_mlme *)extra;
-       struct cfg80211_registered_device *rdev;
-       union {
-               struct cfg80211_disassoc_request disassoc;
-               struct cfg80211_deauth_request deauth;
-       } cmd;
-
-       if (!wdev)
-               return -EOPNOTSUPP;
-
-       rdev = wiphy_to_dev(wdev->wiphy);
-
-       if (wdev->iftype != NL80211_IFTYPE_STATION)
-               return -EINVAL;
-
-       if (mlme->addr.sa_family != ARPHRD_ETHER)
-               return -EINVAL;
-
-       memset(&cmd, 0, sizeof(cmd));
-
-       switch (mlme->cmd) {
-       case IW_MLME_DEAUTH:
-               if (!rdev->ops->deauth)
-                       return -EOPNOTSUPP;
-               cmd.deauth.peer_addr = mlme->addr.sa_data;
-               cmd.deauth.reason_code = mlme->reason_code;
-               return rdev->ops->deauth(wdev->wiphy, dev, &cmd.deauth);
-       case IW_MLME_DISASSOC:
-               if (!rdev->ops->disassoc)
-                       return -EOPNOTSUPP;
-               cmd.disassoc.peer_addr = mlme->addr.sa_data;
-               cmd.disassoc.reason_code = mlme->reason_code;
-               return rdev->ops->disassoc(wdev->wiphy, dev, &cmd.disassoc);
-       default:
-               return -EOPNOTSUPP;
-       }
-}
-EXPORT_SYMBOL_GPL(cfg80211_wext_siwmlme);
-
 
 /**
  * cfg80211_wext_freq - get wext frequency for non-"auto"
@@ -827,3 +801,419 @@ int cfg80211_wext_giwtxpower(struct net_device *dev,
        return 0;
 }
 EXPORT_SYMBOL_GPL(cfg80211_wext_giwtxpower);
+
+static int cfg80211_set_auth_alg(struct wireless_dev *wdev,
+                                s32 auth_alg)
+{
+       int nr_alg = 0;
+
+       if (!auth_alg)
+               return -EINVAL;
+
+       if (auth_alg & ~(IW_AUTH_ALG_OPEN_SYSTEM |
+                        IW_AUTH_ALG_SHARED_KEY |
+                        IW_AUTH_ALG_LEAP))
+               return -EINVAL;
+
+       if (auth_alg & IW_AUTH_ALG_OPEN_SYSTEM) {
+               nr_alg++;
+               wdev->wext.connect.auth_type = NL80211_AUTHTYPE_OPEN_SYSTEM;
+       }
+
+       if (auth_alg & IW_AUTH_ALG_SHARED_KEY) {
+               nr_alg++;
+               wdev->wext.connect.auth_type = NL80211_AUTHTYPE_SHARED_KEY;
+       }
+
+       if (auth_alg & IW_AUTH_ALG_LEAP) {
+               nr_alg++;
+               wdev->wext.connect.auth_type = NL80211_AUTHTYPE_NETWORK_EAP;
+       }
+
+       if (nr_alg > 1)
+               wdev->wext.connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC;
+
+       return 0;
+}
+
+static int cfg80211_set_wpa_version(struct wireless_dev *wdev, u32 wpa_versions)
+{
+       wdev->wext.connect.crypto.wpa_versions = 0;
+
+       if (wpa_versions & ~(IW_AUTH_WPA_VERSION_WPA |
+                            IW_AUTH_WPA_VERSION_WPA2))
+               return -EINVAL;
+
+       if (wpa_versions & IW_AUTH_WPA_VERSION_WPA)
+               wdev->wext.connect.crypto.wpa_versions |=
+                       NL80211_WPA_VERSION_1;
+
+       if (wpa_versions & IW_AUTH_WPA_VERSION_WPA2)
+               wdev->wext.connect.crypto.wpa_versions |=
+                       NL80211_WPA_VERSION_2;
+
+       return 0;
+}
+
+static int cfg80211_set_cipher_group(struct wireless_dev *wdev, u32 cipher)
+{
+       wdev->wext.connect.crypto.cipher_group = 0;
+
+       if (cipher & IW_AUTH_CIPHER_WEP40)
+               wdev->wext.connect.crypto.cipher_group =
+                       WLAN_CIPHER_SUITE_WEP40;
+       else if (cipher & IW_AUTH_CIPHER_WEP104)
+               wdev->wext.connect.crypto.cipher_group =
+                       WLAN_CIPHER_SUITE_WEP104;
+       else if (cipher & IW_AUTH_CIPHER_TKIP)
+               wdev->wext.connect.crypto.cipher_group =
+                       WLAN_CIPHER_SUITE_TKIP;
+       else if (cipher & IW_AUTH_CIPHER_CCMP)
+               wdev->wext.connect.crypto.cipher_group =
+                       WLAN_CIPHER_SUITE_CCMP;
+       else if (cipher & IW_AUTH_CIPHER_AES_CMAC)
+               wdev->wext.connect.crypto.cipher_group =
+                       WLAN_CIPHER_SUITE_AES_CMAC;
+       else
+               return -EINVAL;
+
+       return 0;
+}
+
+static int cfg80211_set_cipher_pairwise(struct wireless_dev *wdev, u32 cipher)
+{
+       int nr_ciphers = 0;
+       u32 *ciphers_pairwise = wdev->wext.connect.crypto.ciphers_pairwise;
+
+       if (cipher & IW_AUTH_CIPHER_WEP40) {
+               ciphers_pairwise[nr_ciphers] = WLAN_CIPHER_SUITE_WEP40;
+               nr_ciphers++;
+       }
+
+       if (cipher & IW_AUTH_CIPHER_WEP104) {
+               ciphers_pairwise[nr_ciphers] = WLAN_CIPHER_SUITE_WEP104;
+               nr_ciphers++;
+       }
+
+       if (cipher & IW_AUTH_CIPHER_TKIP) {
+               ciphers_pairwise[nr_ciphers] = WLAN_CIPHER_SUITE_TKIP;
+               nr_ciphers++;
+       }
+
+       if (cipher & IW_AUTH_CIPHER_CCMP) {
+               ciphers_pairwise[nr_ciphers] = WLAN_CIPHER_SUITE_CCMP;
+               nr_ciphers++;
+       }
+
+       if (cipher & IW_AUTH_CIPHER_AES_CMAC) {
+               ciphers_pairwise[nr_ciphers] = WLAN_CIPHER_SUITE_AES_CMAC;
+               nr_ciphers++;
+       }
+
+       BUILD_BUG_ON(NL80211_MAX_NR_CIPHER_SUITES < 5);
+
+       wdev->wext.connect.crypto.n_ciphers_pairwise = nr_ciphers;
+
+       return 0;
+}
+
+
+static int cfg80211_set_key_mgt(struct wireless_dev *wdev, u32 key_mgt)
+{
+       int nr_akm_suites = 0;
+
+       if (key_mgt & ~(IW_AUTH_KEY_MGMT_802_1X |
+                       IW_AUTH_KEY_MGMT_PSK))
+               return -EINVAL;
+
+       if (key_mgt & IW_AUTH_KEY_MGMT_802_1X) {
+               wdev->wext.connect.crypto.akm_suites[nr_akm_suites] =
+                       WLAN_AKM_SUITE_8021X;
+               nr_akm_suites++;
+       }
+
+       if (key_mgt & IW_AUTH_KEY_MGMT_PSK) {
+               wdev->wext.connect.crypto.akm_suites[nr_akm_suites] =
+                       WLAN_AKM_SUITE_PSK;
+               nr_akm_suites++;
+       }
+
+       wdev->wext.connect.crypto.n_akm_suites = nr_akm_suites;
+
+       return 0;
+}
+
+int cfg80211_wext_siwauth(struct net_device *dev,
+                         struct iw_request_info *info,
+                         struct iw_param *data, char *extra)
+{
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+
+       if (wdev->iftype != NL80211_IFTYPE_STATION)
+               return -EOPNOTSUPP;
+
+       switch (data->flags & IW_AUTH_INDEX) {
+       case IW_AUTH_PRIVACY_INVOKED:
+               wdev->wext.connect.privacy = data->value;
+               return 0;
+       case IW_AUTH_WPA_VERSION:
+               return cfg80211_set_wpa_version(wdev, data->value);
+       case IW_AUTH_CIPHER_GROUP:
+               return cfg80211_set_cipher_group(wdev, data->value);
+       case IW_AUTH_KEY_MGMT:
+               return cfg80211_set_key_mgt(wdev, data->value);
+       case IW_AUTH_CIPHER_PAIRWISE:
+               return cfg80211_set_cipher_pairwise(wdev, data->value);
+       case IW_AUTH_80211_AUTH_ALG:
+               return cfg80211_set_auth_alg(wdev, data->value);
+       case IW_AUTH_WPA_ENABLED:
+       case IW_AUTH_RX_UNENCRYPTED_EAPOL:
+       case IW_AUTH_DROP_UNENCRYPTED:
+       case IW_AUTH_MFP:
+               return 0;
+       default:
+               return -EOPNOTSUPP;
+       }
+}
+EXPORT_SYMBOL_GPL(cfg80211_wext_siwauth);
+
+int cfg80211_wext_giwauth(struct net_device *dev,
+                         struct iw_request_info *info,
+                         struct iw_param *data, char *extra)
+{
+       /* XXX: what do we need? */
+
+       return -EOPNOTSUPP;
+}
+EXPORT_SYMBOL_GPL(cfg80211_wext_giwauth);
+
+int cfg80211_wext_siwpower(struct net_device *dev,
+                          struct iw_request_info *info,
+                          struct iw_param *wrq, char *extra)
+{
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+       bool ps = wdev->wext.ps;
+       int timeout = wdev->wext.ps_timeout;
+       int err;
+
+       if (wdev->iftype != NL80211_IFTYPE_STATION)
+               return -EINVAL;
+
+       if (!rdev->ops->set_power_mgmt)
+               return -EOPNOTSUPP;
+
+       if (wrq->disabled) {
+               ps = false;
+       } else {
+               switch (wrq->flags & IW_POWER_MODE) {
+               case IW_POWER_ON:       /* If not specified */
+               case IW_POWER_MODE:     /* If set all mask */
+               case IW_POWER_ALL_R:    /* If explicitely state all */
+                       ps = true;
+                       break;
+               default:                /* Otherwise we ignore */
+                       return -EINVAL;
+               }
+
+               if (wrq->flags & ~(IW_POWER_MODE | IW_POWER_TIMEOUT))
+                       return -EINVAL;
+
+               if (wrq->flags & IW_POWER_TIMEOUT)
+                       timeout = wrq->value / 1000;
+       }
+
+       err = rdev->ops->set_power_mgmt(wdev->wiphy, dev, ps, timeout);
+       if (err)
+               return err;
+
+       wdev->wext.ps = ps;
+       wdev->wext.ps_timeout = timeout;
+
+       return 0;
+
+}
+EXPORT_SYMBOL_GPL(cfg80211_wext_siwpower);
+
+int cfg80211_wext_giwpower(struct net_device *dev,
+                          struct iw_request_info *info,
+                          struct iw_param *wrq, char *extra)
+{
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+
+       wrq->disabled = !wdev->wext.ps;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(cfg80211_wext_giwpower);
+
+int cfg80211_wds_wext_siwap(struct net_device *dev,
+                           struct iw_request_info *info,
+                           struct sockaddr *addr, char *extra)
+{
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+       int err;
+
+       if (WARN_ON(wdev->iftype != NL80211_IFTYPE_WDS))
+               return -EINVAL;
+
+       if (addr->sa_family != ARPHRD_ETHER)
+               return -EINVAL;
+
+       if (netif_running(dev))
+               return -EBUSY;
+
+       if (!rdev->ops->set_wds_peer)
+               return -EOPNOTSUPP;
+
+       err = rdev->ops->set_wds_peer(wdev->wiphy, dev, (u8 *) &addr->sa_data);
+       if (err)
+               return err;
+
+       memcpy(&wdev->wext.bssid, (u8 *) &addr->sa_data, ETH_ALEN);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(cfg80211_wds_wext_siwap);
+
+int cfg80211_wds_wext_giwap(struct net_device *dev,
+                           struct iw_request_info *info,
+                           struct sockaddr *addr, char *extra)
+{
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+
+       if (WARN_ON(wdev->iftype != NL80211_IFTYPE_WDS))
+               return -EINVAL;
+
+       addr->sa_family = ARPHRD_ETHER;
+       memcpy(&addr->sa_data, wdev->wext.bssid, ETH_ALEN);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(cfg80211_wds_wext_giwap);
+
+int cfg80211_wext_siwrate(struct net_device *dev,
+                         struct iw_request_info *info,
+                         struct iw_param *rate, char *extra)
+{
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+       struct cfg80211_bitrate_mask mask;
+
+       if (!rdev->ops->set_bitrate_mask)
+               return -EOPNOTSUPP;
+
+       mask.fixed = 0;
+       mask.maxrate = 0;
+
+       if (rate->value < 0) {
+               /* nothing */
+       } else if (rate->fixed) {
+               mask.fixed = rate->value / 1000; /* kbps */
+       } else {
+               mask.maxrate = rate->value / 1000; /* kbps */
+       }
+
+       return rdev->ops->set_bitrate_mask(wdev->wiphy, dev, NULL, &mask);
+}
+EXPORT_SYMBOL_GPL(cfg80211_wext_siwrate);
+
+int cfg80211_wext_giwrate(struct net_device *dev,
+                         struct iw_request_info *info,
+                         struct iw_param *rate, char *extra)
+{
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+       /* we are under RTNL - globally locked - so can use a static struct */
+       static struct station_info sinfo;
+       u8 *addr;
+       int err;
+
+       if (wdev->iftype != NL80211_IFTYPE_STATION)
+               return -EOPNOTSUPP;
+
+       if (!rdev->ops->get_station)
+               return -EOPNOTSUPP;
+
+       if (wdev->current_bss)
+               addr = wdev->current_bss->pub.bssid;
+       else if (wdev->wext.connect.bssid)
+               addr = wdev->wext.connect.bssid;
+       else
+               return -EOPNOTSUPP;
+
+       err = rdev->ops->get_station(&rdev->wiphy, dev, addr, &sinfo);
+       if (err)
+               return err;
+
+       if (!(sinfo.filled & STATION_INFO_TX_BITRATE))
+               return -EOPNOTSUPP;
+
+       rate->value = 0;
+
+       if (!(sinfo.txrate.flags & RATE_INFO_FLAGS_MCS))
+               rate->value = 100000 * sinfo.txrate.legacy;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(cfg80211_wext_giwrate);
+
+/* Get wireless statistics.  Called by /proc/net/wireless and by SIOCGIWSTATS */
+struct iw_statistics *cfg80211_wireless_stats(struct net_device *dev)
+{
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+       /* we are under RTNL - globally locked - so can use static structs */
+       static struct iw_statistics wstats;
+       static struct station_info sinfo;
+       u8 *addr;
+
+       if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION)
+               return NULL;
+
+       if (!rdev->ops->get_station)
+               return NULL;
+
+       addr = wdev->wext.connect.bssid;
+       if (!addr)
+               return NULL;
+
+       if (rdev->ops->get_station(&rdev->wiphy, dev, addr, &sinfo))
+               return NULL;
+
+       memset(&wstats, 0, sizeof(wstats));
+
+       switch (rdev->wiphy.signal_type) {
+       case CFG80211_SIGNAL_TYPE_MBM:
+               if (sinfo.filled & STATION_INFO_SIGNAL) {
+                       int sig = sinfo.signal;
+                       wstats.qual.updated |= IW_QUAL_LEVEL_UPDATED;
+                       wstats.qual.updated |= IW_QUAL_QUAL_UPDATED;
+                       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;
+                       break;
+               }
+       case CFG80211_SIGNAL_TYPE_UNSPEC:
+               if (sinfo.filled & STATION_INFO_SIGNAL) {
+                       wstats.qual.updated |= IW_QUAL_LEVEL_UPDATED;
+                       wstats.qual.updated |= IW_QUAL_QUAL_UPDATED;
+                       wstats.qual.level = sinfo.signal;
+                       wstats.qual.qual = sinfo.signal;
+                       break;
+               }
+       default:
+               wstats.qual.updated |= IW_QUAL_LEVEL_INVALID;
+               wstats.qual.updated |= IW_QUAL_QUAL_INVALID;
+       }
+
+       wstats.qual.updated |= IW_QUAL_NOISE_INVALID;
+
+       return &wstats;
+}
+EXPORT_SYMBOL_GPL(cfg80211_wireless_stats);
diff --git a/net/wireless/wext-sme.c b/net/wireless/wext-sme.c
new file mode 100644 (file)
index 0000000..6f75aaa
--- /dev/null
@@ -0,0 +1,380 @@
+/*
+ * cfg80211 wext compat for managed mode.
+ *
+ * Copyright 2009      Johannes Berg <johannes@sipsolutions.net>
+ * Copyright (C) 2009   Intel Corporation. All rights reserved.
+ */
+
+#include <linux/etherdevice.h>
+#include <linux/if_arp.h>
+#include <net/cfg80211.h>
+#include "nl80211.h"
+
+static int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev,
+                                    struct wireless_dev *wdev)
+{
+       int err;
+
+       ASSERT_RDEV_LOCK(rdev);
+       ASSERT_WDEV_LOCK(wdev);
+
+       if (!netif_running(wdev->netdev))
+               return 0;
+
+       wdev->wext.connect.ie = wdev->wext.ie;
+       wdev->wext.connect.ie_len = wdev->wext.ie_len;
+       wdev->wext.connect.privacy = wdev->wext.default_key != -1;
+
+       err = 0;
+       if (wdev->wext.connect.ssid_len != 0)
+               err = __cfg80211_connect(rdev, wdev->netdev,
+                                        &wdev->wext.connect);
+
+       return err;
+}
+
+int cfg80211_mgd_wext_siwfreq(struct net_device *dev,
+                             struct iw_request_info *info,
+                             struct iw_freq *freq, char *extra)
+{
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+       struct ieee80211_channel *chan;
+       int err;
+
+       /* call only for station! */
+       if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION))
+               return -EINVAL;
+
+       chan = cfg80211_wext_freq(wdev->wiphy, freq);
+       if (chan && IS_ERR(chan))
+               return PTR_ERR(chan);
+
+       if (chan && (chan->flags & IEEE80211_CHAN_DISABLED))
+               return -EINVAL;
+
+       cfg80211_lock_rdev(rdev);
+       wdev_lock(wdev);
+
+       if (wdev->wext.connect.channel == chan) {
+               err = 0;
+               goto out;
+       }
+
+       if (wdev->sme_state != CFG80211_SME_IDLE) {
+               bool event = true;
+               /* if SSID set, we'll try right again, avoid event */
+               if (wdev->wext.connect.ssid_len)
+                       event = false;
+               err = __cfg80211_disconnect(wiphy_to_dev(wdev->wiphy),
+                                           dev, WLAN_REASON_DEAUTH_LEAVING,
+                                           event);
+               if (err)
+                       goto out;
+       }
+
+
+       wdev->wext.connect.channel = chan;
+
+       /* SSID is not set, we just want to switch channel */
+       if (wdev->wext.connect.ssid_len && chan) {
+               err = -EOPNOTSUPP;
+               if (rdev->ops->set_channel)
+                       err = rdev->ops->set_channel(wdev->wiphy, chan,
+                                                    NL80211_CHAN_NO_HT);
+               goto out;
+       }
+
+       err = cfg80211_mgd_wext_connect(wiphy_to_dev(wdev->wiphy), wdev);
+ out:
+       wdev_unlock(wdev);
+       cfg80211_unlock_rdev(rdev);
+       return err;
+}
+/* temporary symbol - mark GPL - in the future the handler won't be */
+EXPORT_SYMBOL_GPL(cfg80211_mgd_wext_siwfreq);
+
+int cfg80211_mgd_wext_giwfreq(struct net_device *dev,
+                             struct iw_request_info *info,
+                             struct iw_freq *freq, char *extra)
+{
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+       struct ieee80211_channel *chan = NULL;
+
+       /* call only for station! */
+       if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION))
+               return -EINVAL;
+
+       wdev_lock(wdev);
+       if (wdev->current_bss)
+               chan = wdev->current_bss->pub.channel;
+       else if (wdev->wext.connect.channel)
+               chan = wdev->wext.connect.channel;
+       wdev_unlock(wdev);
+
+       if (chan) {
+               freq->m = chan->center_freq;
+               freq->e = 6;
+               return 0;
+       }
+
+       /* no channel if not joining */
+       return -EINVAL;
+}
+/* temporary symbol - mark GPL - in the future the handler won't be */
+EXPORT_SYMBOL_GPL(cfg80211_mgd_wext_giwfreq);
+
+int cfg80211_mgd_wext_siwessid(struct net_device *dev,
+                              struct iw_request_info *info,
+                              struct iw_point *data, char *ssid)
+{
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+       size_t len = data->length;
+       int err;
+
+       /* call only for station! */
+       if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION))
+               return -EINVAL;
+
+       if (!data->flags)
+               len = 0;
+
+       /* iwconfig uses nul termination in SSID.. */
+       if (len > 0 && ssid[len - 1] == '\0')
+               len--;
+
+       cfg80211_lock_rdev(wiphy_to_dev(wdev->wiphy));
+       wdev_lock(wdev);
+
+       err = 0;
+
+       if (wdev->wext.connect.ssid && len &&
+           len == wdev->wext.connect.ssid_len &&
+           memcmp(wdev->wext.connect.ssid, ssid, len))
+               goto out;
+
+       if (wdev->sme_state != CFG80211_SME_IDLE) {
+               bool event = true;
+               /* if SSID set now, we'll try to connect, avoid event */
+               if (len)
+                       event = false;
+               err = __cfg80211_disconnect(wiphy_to_dev(wdev->wiphy),
+                                           dev, WLAN_REASON_DEAUTH_LEAVING,
+                                           event);
+               if (err)
+                       goto out;
+       }
+
+       wdev->wext.connect.ssid = wdev->wext.ssid;
+       memcpy(wdev->wext.ssid, ssid, len);
+       wdev->wext.connect.ssid_len = len;
+
+       wdev->wext.connect.crypto.control_port = false;
+
+       err = cfg80211_mgd_wext_connect(wiphy_to_dev(wdev->wiphy), wdev);
+ out:
+       wdev_unlock(wdev);
+       cfg80211_unlock_rdev(wiphy_to_dev(wdev->wiphy));
+       return err;
+}
+/* temporary symbol - mark GPL - in the future the handler won't be */
+EXPORT_SYMBOL_GPL(cfg80211_mgd_wext_siwessid);
+
+int cfg80211_mgd_wext_giwessid(struct net_device *dev,
+                              struct iw_request_info *info,
+                              struct iw_point *data, char *ssid)
+{
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+
+       /* call only for station! */
+       if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION))
+               return -EINVAL;
+
+       data->flags = 0;
+
+       wdev_lock(wdev);
+       if (wdev->ssid_len) {
+               data->flags = 1;
+               data->length = wdev->ssid_len;
+               memcpy(ssid, wdev->ssid, data->length);
+       } else if (wdev->wext.connect.ssid && wdev->wext.connect.ssid_len) {
+               data->flags = 1;
+               data->length = wdev->wext.connect.ssid_len;
+               memcpy(ssid, wdev->wext.connect.ssid, data->length);
+       } else
+               data->flags = 0;
+       wdev_unlock(wdev);
+
+       return 0;
+}
+/* temporary symbol - mark GPL - in the future the handler won't be */
+EXPORT_SYMBOL_GPL(cfg80211_mgd_wext_giwessid);
+
+int cfg80211_mgd_wext_siwap(struct net_device *dev,
+                           struct iw_request_info *info,
+                           struct sockaddr *ap_addr, char *extra)
+{
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+       u8 *bssid = ap_addr->sa_data;
+       int err;
+
+       /* call only for station! */
+       if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION))
+               return -EINVAL;
+
+       if (ap_addr->sa_family != ARPHRD_ETHER)
+               return -EINVAL;
+
+       /* automatic mode */
+       if (is_zero_ether_addr(bssid) || is_broadcast_ether_addr(bssid))
+               bssid = NULL;
+
+       cfg80211_lock_rdev(wiphy_to_dev(wdev->wiphy));
+       wdev_lock(wdev);
+
+       err = 0;
+       /* both automatic */
+       if (!bssid && !wdev->wext.connect.bssid)
+               goto out;
+
+       /* fixed already - and no change */
+       if (wdev->wext.connect.bssid && bssid &&
+           compare_ether_addr(bssid, wdev->wext.connect.bssid) == 0)
+               goto out;
+
+       if (wdev->sme_state != CFG80211_SME_IDLE) {
+               err = __cfg80211_disconnect(wiphy_to_dev(wdev->wiphy),
+                                           dev, WLAN_REASON_DEAUTH_LEAVING,
+                                           false);
+               if (err)
+                       goto out;
+       }
+
+       if (bssid) {
+               memcpy(wdev->wext.bssid, bssid, ETH_ALEN);
+               wdev->wext.connect.bssid = wdev->wext.bssid;
+       } else
+               wdev->wext.connect.bssid = NULL;
+
+       err = cfg80211_mgd_wext_connect(wiphy_to_dev(wdev->wiphy), wdev);
+ out:
+       wdev_unlock(wdev);
+       cfg80211_unlock_rdev(wiphy_to_dev(wdev->wiphy));
+       return err;
+}
+/* temporary symbol - mark GPL - in the future the handler won't be */
+EXPORT_SYMBOL_GPL(cfg80211_mgd_wext_siwap);
+
+int cfg80211_mgd_wext_giwap(struct net_device *dev,
+                           struct iw_request_info *info,
+                           struct sockaddr *ap_addr, char *extra)
+{
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+
+       /* call only for station! */
+       if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION))
+               return -EINVAL;
+
+       ap_addr->sa_family = ARPHRD_ETHER;
+
+       wdev_lock(wdev);
+       if (wdev->current_bss)
+               memcpy(ap_addr->sa_data, wdev->current_bss->pub.bssid, ETH_ALEN);
+       else if (wdev->wext.connect.bssid)
+               memcpy(ap_addr->sa_data, wdev->wext.connect.bssid, ETH_ALEN);
+       else
+               memset(ap_addr->sa_data, 0, ETH_ALEN);
+       wdev_unlock(wdev);
+
+       return 0;
+}
+/* temporary symbol - mark GPL - in the future the handler won't be */
+EXPORT_SYMBOL_GPL(cfg80211_mgd_wext_giwap);
+
+int cfg80211_wext_siwgenie(struct net_device *dev,
+                          struct iw_request_info *info,
+                          struct iw_point *data, char *extra)
+{
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+       u8 *ie = extra;
+       int ie_len = data->length, err;
+
+       if (wdev->iftype != NL80211_IFTYPE_STATION)
+               return -EOPNOTSUPP;
+
+       if (!ie_len)
+               ie = NULL;
+
+       wdev_lock(wdev);
+
+       /* no change */
+       err = 0;
+       if (wdev->wext.ie_len == ie_len &&
+           memcmp(wdev->wext.ie, ie, ie_len) == 0)
+               goto out;
+
+       if (ie_len) {
+               ie = kmemdup(extra, ie_len, GFP_KERNEL);
+               if (!ie) {
+                       err = -ENOMEM;
+                       goto out;
+               }
+       } else
+               ie = NULL;
+
+       kfree(wdev->wext.ie);
+       wdev->wext.ie = ie;
+       wdev->wext.ie_len = ie_len;
+
+       if (wdev->sme_state != CFG80211_SME_IDLE) {
+               err = __cfg80211_disconnect(rdev, dev,
+                                           WLAN_REASON_DEAUTH_LEAVING, false);
+               if (err)
+                       goto out;
+       }
+
+       /* userspace better not think we'll reconnect */
+       err = 0;
+ out:
+       wdev_unlock(wdev);
+       return err;
+}
+EXPORT_SYMBOL_GPL(cfg80211_wext_siwgenie);
+
+int cfg80211_wext_siwmlme(struct net_device *dev,
+                         struct iw_request_info *info,
+                         struct iw_point *data, char *extra)
+{
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+       struct iw_mlme *mlme = (struct iw_mlme *)extra;
+       struct cfg80211_registered_device *rdev;
+       int err;
+
+       if (!wdev)
+               return -EOPNOTSUPP;
+
+       rdev = wiphy_to_dev(wdev->wiphy);
+
+       if (wdev->iftype != NL80211_IFTYPE_STATION)
+               return -EINVAL;
+
+       if (mlme->addr.sa_family != ARPHRD_ETHER)
+               return -EINVAL;
+
+       wdev_lock(wdev);
+       switch (mlme->cmd) {
+       case IW_MLME_DEAUTH:
+       case IW_MLME_DISASSOC:
+               err = __cfg80211_disconnect(rdev, dev, mlme->reason_code,
+                                           true);
+               break;
+       default:
+               err = -EOPNOTSUPP;
+               break;
+       }
+       wdev_unlock(wdev);
+
+       return err;
+}
+EXPORT_SYMBOL_GPL(cfg80211_wext_siwmlme);
index 252c201..3fe3c2c 100644 (file)
@@ -417,6 +417,21 @@ static const int event_type_size[] = {
        IW_EV_QUAL_LEN,                 /* IW_HEADER_TYPE_QUAL */
 };
 
+#ifdef CONFIG_COMPAT
+static const int compat_event_type_size[] = {
+       IW_EV_COMPAT_LCP_LEN,           /* IW_HEADER_TYPE_NULL */
+       0,
+       IW_EV_COMPAT_CHAR_LEN,          /* IW_HEADER_TYPE_CHAR */
+       0,
+       IW_EV_COMPAT_UINT_LEN,          /* IW_HEADER_TYPE_UINT */
+       IW_EV_COMPAT_FREQ_LEN,          /* IW_HEADER_TYPE_FREQ */
+       IW_EV_COMPAT_ADDR_LEN,          /* IW_HEADER_TYPE_ADDR */
+       0,
+       IW_EV_COMPAT_POINT_LEN,         /* Without variable payload */
+       IW_EV_COMPAT_PARAM_LEN,         /* IW_HEADER_TYPE_PARAM */
+       IW_EV_COMPAT_QUAL_LEN,          /* IW_HEADER_TYPE_QUAL */
+};
+#endif
 
 /************************ COMMON SUBROUTINES ************************/
 /*
@@ -610,6 +625,11 @@ static void wireless_seq_printf_stats(struct seq_file *seq,
 {
        /* Get stats from the driver */
        struct iw_statistics *stats = get_wireless_stats(dev);
+       static struct iw_statistics nullstats = {};
+
+       /* show device if it's wireless regardless of current stats */
+       if (!stats && dev->wireless_handlers)
+               stats = &nullstats;
 
        if (stats) {
                seq_printf(seq, "%6s: %04x  %3d%c  %3d%c  %3d%c  %6d %6d %6d "
@@ -628,7 +648,9 @@ static void wireless_seq_printf_stats(struct seq_file *seq,
                           stats->discard.nwid, stats->discard.code,
                           stats->discard.fragment, stats->discard.retries,
                           stats->discard.misc, stats->miss.beacon);
-               stats->qual.updated &= ~IW_QUAL_ALL_UPDATED;
+
+               if (stats != &nullstats)
+                       stats->qual.updated &= ~IW_QUAL_ALL_UPDATED;
        }
 }
 
@@ -1250,65 +1272,58 @@ int compat_wext_handle_ioctl(struct net *net, unsigned int cmd,
 }
 #endif
 
-/************************* EVENT PROCESSING *************************/
-/*
- * Process events generated by the wireless layer or the driver.
- * Most often, the event will be propagated through rtnetlink
- */
+static int __net_init wext_pernet_init(struct net *net)
+{
+       skb_queue_head_init(&net->wext_nlevents);
+       return 0;
+}
 
-/* ---------------------------------------------------------------- */
-/*
- * Locking...
- * ----------
- *
- * Thanks to Herbert Xu <herbert@gondor.apana.org.au> for fixing
- * the locking issue in here and implementing this code !
- *
- * The issue : wireless_send_event() is often called in interrupt context,
- * while the Netlink layer can never be called in interrupt context.
- * The fully formed RtNetlink events are queued, and then a tasklet is run
- * to feed those to Netlink.
- * The skb_queue is interrupt safe, and its lock is not held while calling
- * Netlink, so there is no possibility of dealock.
- * Jean II
- */
+static void __net_exit wext_pernet_exit(struct net *net)
+{
+       skb_queue_purge(&net->wext_nlevents);
+}
 
-static struct sk_buff_head wireless_nlevent_queue;
+static struct pernet_operations wext_pernet_ops = {
+       .init = wext_pernet_init,
+       .exit = wext_pernet_exit,
+};
 
 static int __init wireless_nlevent_init(void)
 {
-       skb_queue_head_init(&wireless_nlevent_queue);
+       return register_pernet_subsys(&wext_pernet_ops);
        return 0;
 }
 
 subsys_initcall(wireless_nlevent_init);
 
-static void wireless_nlevent_process(unsigned long data)
+/* Process events generated by the wireless layer or the driver. */
+static void wireless_nlevent_process(struct work_struct *work)
 {
        struct sk_buff *skb;
+       struct net *net;
+
+       rtnl_lock();
+
+       for_each_net(net) {
+               while ((skb = skb_dequeue(&net->wext_nlevents)))
+                       rtnl_notify(skb, net, 0, RTNLGRP_LINK, NULL,
+                                   GFP_KERNEL);
+       }
 
-       while ((skb = skb_dequeue(&wireless_nlevent_queue)))
-               rtnl_notify(skb, &init_net, 0, RTNLGRP_LINK, NULL, GFP_ATOMIC);
+       rtnl_unlock();
 }
 
-static DECLARE_TASKLET(wireless_nlevent_tasklet, wireless_nlevent_process, 0);
+static DECLARE_WORK(wireless_nlevent_work, wireless_nlevent_process);
 
-/* ---------------------------------------------------------------- */
-/*
- * Fill a rtnetlink message with our event data.
- * Note that we propage only the specified event and don't dump the
- * current wireless config. Dumping the wireless config is far too
- * expensive (for each parameter, the driver need to query the hardware).
- */
-static int rtnetlink_fill_iwinfo(struct sk_buff *skb, struct net_device *dev,
-                                int type, char *event, int event_len)
+static struct nlmsghdr *rtnetlink_ifinfo_prep(struct net_device *dev,
+                                             struct sk_buff *skb)
 {
        struct ifinfomsg *r;
        struct nlmsghdr  *nlh;
 
-       nlh = nlmsg_put(skb, 0, 0, type, sizeof(*r), 0);
-       if (nlh == NULL)
-               return -EMSGSIZE;
+       nlh = nlmsg_put(skb, 0, 0, RTM_NEWLINK, sizeof(*r), 0);
+       if (!nlh)
+               return NULL;
 
        r = nlmsg_data(nlh);
        r->ifi_family = AF_UNSPEC;
@@ -1319,48 +1334,14 @@ static int rtnetlink_fill_iwinfo(struct sk_buff *skb, struct net_device *dev,
        r->ifi_change = 0;      /* Wireless changes don't affect those flags */
 
        NLA_PUT_STRING(skb, IFLA_IFNAME, dev->name);
-       /* Add the wireless events in the netlink packet */
-       NLA_PUT(skb, IFLA_WIRELESS, event_len, event);
 
-       return nlmsg_end(skb, nlh);
-
-nla_put_failure:
+       return nlh;
+ nla_put_failure:
        nlmsg_cancel(skb, nlh);
-       return -EMSGSIZE;
+       return NULL;
 }
 
-/* ---------------------------------------------------------------- */
-/*
- * Create and broadcast and send it on the standard rtnetlink socket
- * This is a pure clone rtmsg_ifinfo() in net/core/rtnetlink.c
- * Andrzej Krzysztofowicz mandated that I used a IFLA_XXX field
- * within a RTM_NEWLINK event.
- */
-static void rtmsg_iwinfo(struct net_device *dev, char *event, int event_len)
-{
-       struct sk_buff *skb;
-       int err;
-
-       if (!net_eq(dev_net(dev), &init_net))
-               return;
-
-       skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
-       if (!skb)
-               return;
-
-       err = rtnetlink_fill_iwinfo(skb, dev, RTM_NEWLINK, event, event_len);
-       if (err < 0) {
-               WARN_ON(err == -EMSGSIZE);
-               kfree_skb(skb);
-               return;
-       }
-
-       NETLINK_CB(skb).dst_group = RTNLGRP_LINK;
-       skb_queue_tail(&wireless_nlevent_queue, skb);
-       tasklet_schedule(&wireless_nlevent_tasklet);
-}
 
-/* ---------------------------------------------------------------- */
 /*
  * Main event dispatcher. Called from other parts and drivers.
  * Send the event on the appropriate channels.
@@ -1369,7 +1350,7 @@ static void rtmsg_iwinfo(struct net_device *dev, char *event, int event_len)
 void wireless_send_event(struct net_device *   dev,
                         unsigned int           cmd,
                         union iwreq_data *     wrqu,
-                        char *                 extra)
+                        const char *           extra)
 {
        const struct iw_ioctl_description *     descr = NULL;
        int extra_len = 0;
@@ -1379,6 +1360,25 @@ void wireless_send_event(struct net_device *     dev,
        int wrqu_off = 0;                       /* Offset in wrqu */
        /* Don't "optimise" the following variable, it will crash */
        unsigned        cmd_index;              /* *MUST* be unsigned */
+       struct sk_buff *skb;
+       struct nlmsghdr *nlh;
+       struct nlattr *nla;
+#ifdef CONFIG_COMPAT
+       struct __compat_iw_event *compat_event;
+       struct compat_iw_point compat_wrqu;
+       struct sk_buff *compskb;
+#endif
+
+       /*
+        * Nothing in the kernel sends scan events with data, be safe.
+        * This is necessary because we cannot fix up scan event data
+        * for compat, due to being contained in 'extra', but normally
+        * applications are required to retrieve the scan data anyway
+        * and no data is included in the event, this codifies that
+        * practice.
+        */
+       if (WARN_ON(cmd == SIOCGIWSCAN && extra))
+               extra = NULL;
 
        /* Get the description of the Event */
        if (cmd <= SIOCIWLAST) {
@@ -1426,25 +1426,107 @@ void wireless_send_event(struct net_device *   dev,
        hdr_len = event_type_size[descr->header_type];
        event_len = hdr_len + extra_len;
 
-       /* Create temporary buffer to hold the event */
-       event = kmalloc(event_len, GFP_ATOMIC);
-       if (event == NULL)
+       /*
+        * The problem for 64/32 bit.
+        *
+        * On 64-bit, a regular event is laid out as follows:
+        *      |  0  |  1  |  2  |  3  |  4  |  5  |  6  |  7  |
+        *      | event.len | event.cmd |     p a d d i n g     |
+        *      | wrqu data ... (with the correct size)         |
+        *
+        * This padding exists because we manipulate event->u,
+        * and 'event' is not packed.
+        *
+        * An iw_point event is laid out like this instead:
+        *      |  0  |  1  |  2  |  3  |  4  |  5  |  6  |  7  |
+        *      | event.len | event.cmd |     p a d d i n g     |
+        *      | iwpnt.len | iwpnt.flg |     p a d d i n g     |
+        *      | extra data  ...
+        *
+        * The second padding exists because struct iw_point is extended,
+        * but this depends on the platform...
+        *
+        * On 32-bit, all the padding shouldn't be there.
+        */
+
+       skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
+       if (!skb)
+               return;
+
+       /* Send via the RtNetlink event channel */
+       nlh = rtnetlink_ifinfo_prep(dev, skb);
+       if (WARN_ON(!nlh)) {
+               kfree_skb(skb);
+               return;
+       }
+
+       /* Add the wireless events in the netlink packet */
+       nla = nla_reserve(skb, IFLA_WIRELESS, event_len);
+       if (!nla) {
+               kfree_skb(skb);
                return;
+       }
+       event = nla_data(nla);
 
-       /* Fill event */
+       /* Fill event - first clear to avoid data leaking */
+       memset(event, 0, hdr_len);
        event->len = event_len;
        event->cmd = cmd;
        memcpy(&event->u, ((char *) wrqu) + wrqu_off, hdr_len - IW_EV_LCP_LEN);
-       if (extra)
+       if (extra_len)
                memcpy(((char *) event) + hdr_len, extra, extra_len);
 
+       nlmsg_end(skb, nlh);
+#ifdef CONFIG_COMPAT
+       hdr_len = compat_event_type_size[descr->header_type];
+       event_len = hdr_len + extra_len;
+
+       compskb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
+       if (!compskb) {
+               kfree_skb(skb);
+               return;
+       }
+
        /* Send via the RtNetlink event channel */
-       rtmsg_iwinfo(dev, (char *) event, event_len);
+       nlh = rtnetlink_ifinfo_prep(dev, compskb);
+       if (WARN_ON(!nlh)) {
+               kfree_skb(skb);
+               kfree_skb(compskb);
+               return;
+       }
 
-       /* Cleanup */
-       kfree(event);
+       /* Add the wireless events in the netlink packet */
+       nla = nla_reserve(compskb, IFLA_WIRELESS, event_len);
+       if (!nla) {
+               kfree_skb(skb);
+               kfree_skb(compskb);
+               return;
+       }
+       compat_event = nla_data(nla);
 
-       return;         /* Always success, I guess ;-) */
+       compat_event->len = event_len;
+       compat_event->cmd = cmd;
+       if (descr->header_type == IW_HEADER_TYPE_POINT) {
+               compat_wrqu.length = wrqu->data.length;
+               compat_wrqu.flags = wrqu->data.flags;
+               memcpy(&compat_event->pointer,
+                       ((char *) &compat_wrqu) + IW_EV_COMPAT_POINT_OFF,
+                       hdr_len - IW_EV_COMPAT_LCP_LEN);
+               if (extra_len)
+                       memcpy(((char *) compat_event) + hdr_len,
+                               extra, extra_len);
+       } else {
+               /* extra_len must be zero, so no if (extra) needed */
+               memcpy(&compat_event->pointer, wrqu,
+                       hdr_len - IW_EV_COMPAT_LCP_LEN);
+       }
+
+       nlmsg_end(compskb, nlh);
+
+       skb_shinfo(skb)->frag_list = compskb;
+#endif
+       skb_queue_tail(&dev_net(dev)->wext_nlevents, skb);
+       schedule_work(&wireless_nlevent_work);
 }
 EXPORT_SYMBOL(wireless_send_event);
 
index b939fbd..52cab46 100644 (file)
@@ -7,3 +7,4 @@ pnmtologo
 bin2c
 unifdef
 binoffset
+ihex2fw
diff --git a/scripts/dtc/.gitignore b/scripts/dtc/.gitignore
new file mode 100644 (file)
index 0000000..095acb4
--- /dev/null
@@ -0,0 +1,5 @@
+dtc
+dtc-lexer.lex.c
+dtc-parser.tab.c
+dtc-parser.tab.h
+
index ed591e9..b52d340 100755 (executable)
@@ -1426,6 +1426,8 @@ sub dump_struct($$) {
        # strip comments:
        $members =~ s/\/\*.*?\*\///gos;
        $nested =~ s/\/\*.*?\*\///gos;
+       # strip kmemcheck_bitfield_{begin,end}.*;
+       $members =~ s/kmemcheck_bitfield_.*?;//gos;
 
        create_parameterlist($members, ';', $file);
        check_sections($file, $declaration_name, "struct", $sectcheck, $struct_actual, $nested);
@@ -1468,8 +1470,6 @@ sub dump_enum($$) {
            }
 
        }
-       # strip kmemcheck_bitfield_{begin,end}.*;
-       $members =~ s/kmemcheck_bitfield_.*?;//gos;
 
        output_declaration($declaration_name,
                           'enum',
index 01c2d13..b19f1f4 100644 (file)
@@ -16,6 +16,8 @@ create_package() {
        local pname="$1" pdir="$2"
 
        cp debian/copyright "$pdir/usr/share/doc/$pname/"
+       cp debian/changelog "$pdir/usr/share/doc/$pname/changelog.Debian"
+       gzip -9 "$pdir/usr/share/doc/$pname/changelog.Debian"
 
        # Fix ownership and permissions
        chown -R root:root "$pdir"
index 64f5ddb..5c11312 100644 (file)
@@ -237,7 +237,7 @@ static void write_header(void)
     fprintf(out, " *  Linux logo %s\n", logoname);
     fputs(" */\n\n", out);
     fputs("#include <linux/linux_logo.h>\n\n", out);
-    fprintf(out, "static const unsigned char %s_data[] __initconst = {\n",
+    fprintf(out, "static unsigned char %s_data[] __initdata = {\n",
            logoname);
 }
 
@@ -374,7 +374,7 @@ static void write_logo_clut224(void)
     fputs("\n};\n\n", out);
 
     /* write logo clut */
-    fprintf(out, "static const unsigned char %s_clut[] __initconst = {\n",
+    fprintf(out, "static unsigned char %s_clut[] __initdata = {\n",
            logoname);
     write_hex_cnt = 0;
     for (i = 0; i < logo_clutsize; i++) {
index 6f61187..101c512 100644 (file)
@@ -238,7 +238,34 @@ out:
 }
 
 /*
- * ima_opens_get - increment file counts
+ * ima_counts_put - decrement file counts
+ *
+ * File counts are incremented in ima_path_check. On file open
+ * error, such as ETXTBSY, decrement the counts to prevent
+ * unnecessary imbalance messages.
+ */
+void ima_counts_put(struct path *path, int mask)
+{
+       struct inode *inode = path->dentry->d_inode;
+       struct ima_iint_cache *iint;
+
+       if (!ima_initialized || !S_ISREG(inode->i_mode))
+               return;
+       iint = ima_iint_find_insert_get(inode);
+       if (!iint)
+               return;
+
+       mutex_lock(&iint->mutex);
+       iint->opencount--;
+       if ((mask & MAY_WRITE) || (mask == 0))
+               iint->writecount--;
+       else if (mask & (MAY_READ | MAY_EXEC))
+               iint->readcount--;
+       mutex_unlock(&iint->mutex);
+}
+
+/*
+ * ima_counts_get - increment file counts
  *
  * - for IPC shm and shmat file.
  * - for nfsd exported files.
index 7ec9431..a0880e9 100644 (file)
@@ -134,7 +134,8 @@ int ima_add_template_entry(struct ima_template_entry *entry, int violation,
        }
 out:
        mutex_unlock(&ima_extend_list_mutex);
-       integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode, entry->template_name,
+       integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode,
+                           entry->template.file_name,
                            op, audit_cause, result, audit_info);
        return result;
 }
index de83608..3ee0269 100644 (file)
@@ -338,7 +338,7 @@ static int __devinit snd_cmi8330_pnp(int dev, struct snd_cmi8330 *acard,
                return -EBUSY;
 
        acard->mpu = pnp_request_card_device(card, id->devs[2].id, NULL);
-       if (acard->play == NULL)
+       if (acard->mpu == NULL)
                return -EBUSY;
 
        pdev = acard->cap;
index c180598..89466b0 100644 (file)
@@ -199,7 +199,7 @@ MODULE_LICENSE("GPL");
  */
 
 static struct pci_device_id id_tbl[] = {
-       { PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5530_AUDIO, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+       { PCI_VDEVICE(CYRIX, PCI_DEVICE_ID_CYRIX_5530_AUDIO), 0 },
        { }
 };
 
index 6c0a770..1b2316f 100644 (file)
@@ -926,31 +926,21 @@ static struct midi_operations mpu401_midi_operations[MAX_MIDI_DEV];
 static void mpu401_chk_version(int n, struct mpu_config *devc)
 {
        int tmp;
-       unsigned long flags;
 
        devc->version = devc->revision = 0;
 
-       spin_lock_irqsave(&devc->lock,flags);
-       if ((tmp = mpu_cmd(n, 0xAC, 0)) < 0)
-       {
-               spin_unlock_irqrestore(&devc->lock,flags);
+       tmp = mpu_cmd(n, 0xAC, 0);
+       if (tmp < 0)
                return;
-       }
        if ((tmp & 0xf0) > 0x20)        /* Why it's larger than 2.x ??? */
-       {
-               spin_unlock_irqrestore(&devc->lock,flags);
                return;
-       }
        devc->version = tmp;
 
-       if ((tmp = mpu_cmd(n, 0xAD, 0)) < 0)
-       {
+       if ((tmp = mpu_cmd(n, 0xAD, 0)) < 0) {
                devc->version = 0;
-               spin_unlock_irqrestore(&devc->lock,flags);
                return;
        }
        devc->revision = tmp;
-       spin_unlock_irqrestore(&devc->lock,flags);
 }
 
 int attach_mpu401(struct address_info *hw_config, struct module *owner)
index 71515dd..d6752df 100644 (file)
@@ -287,10 +287,10 @@ struct atiixp {
 /*
  */
 static struct pci_device_id snd_atiixp_ids[] = {
-       { 0x1002, 0x4341, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* SB200 */
-       { 0x1002, 0x4361, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* SB300 */
-       { 0x1002, 0x4370, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* SB400 */
-       { 0x1002, 0x4382, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* SB600 */
+       { PCI_VDEVICE(ATI, 0x4341), 0 }, /* SB200 */
+       { PCI_VDEVICE(ATI, 0x4361), 0 }, /* SB300 */
+       { PCI_VDEVICE(ATI, 0x4370), 0 }, /* SB400 */
+       { PCI_VDEVICE(ATI, 0x4382), 0 }, /* SB600 */
        { 0, }
 };
 
index c3136cc..e7e147b 100644 (file)
@@ -262,8 +262,8 @@ struct atiixp_modem {
 /*
  */
 static struct pci_device_id snd_atiixp_ids[] = {
-       { 0x1002, 0x434d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* SB200 */
-       { 0x1002, 0x4378, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* SB400 */
+       { PCI_VDEVICE(ATI, 0x434d), 0 }, /* SB200 */
+       { PCI_VDEVICE(ATI, 0x4378), 0 }, /* SB400 */
        { 0, }
 };
 
index fce22c7..c0e8c6b 100644 (file)
@@ -1,8 +1,7 @@
 #include "au8810.h"
 #include "au88x0.h"
 static struct pci_device_id snd_vortex_ids[] = {
-       {PCI_VENDOR_ID_AUREAL, PCI_DEVICE_ID_AUREAL_ADVANTAGE,
-        PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1,},
+       {PCI_VDEVICE(AUREAL, PCI_DEVICE_ID_AUREAL_ADVANTAGE), 1,},
        {0,}
 };
 
index d1fbcce..a652733 100644 (file)
@@ -1,8 +1,7 @@
 #include "au8820.h"
 #include "au88x0.h"
 static struct pci_device_id snd_vortex_ids[] = {
-       {PCI_VENDOR_ID_AUREAL, PCI_DEVICE_ID_AUREAL_VORTEX_1,
-        PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0,},
+       {PCI_VDEVICE(AUREAL, PCI_DEVICE_ID_AUREAL_VORTEX_1), 0,},
        {0,}
 };
 
index d4f2717..6c702ad 100644 (file)
@@ -1,8 +1,7 @@
 #include "au8830.h"
 #include "au88x0.h"
 static struct pci_device_id snd_vortex_ids[] = {
-       {PCI_VENDOR_ID_AUREAL, PCI_DEVICE_ID_AUREAL_VORTEX_2,
-        PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0,},
+       {PCI_VDEVICE(AUREAL, PCI_DEVICE_ID_AUREAL_VORTEX_2), 0,},
        {0,}
 };
 
index 57b992a..f24bf1e 100644 (file)
@@ -1876,7 +1876,7 @@ static int snd_ca0106_resume(struct pci_dev *pci)
 
 // PCI IDs
 static struct pci_device_id snd_ca0106_ids[] = {
-       { 0x1102, 0x0007, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },    /* Audigy LS or Live 24bit */
+       { PCI_VDEVICE(CREATIVE, 0x0007), 0 },   /* Audigy LS or Live 24bit */
        { 0, }
 };
 MODULE_DEVICE_TABLE(pci, snd_ca0106_ids);
index 449fe02..ddcd4a9 100644 (file)
@@ -2797,11 +2797,11 @@ static inline void snd_cmipci_proc_init(struct cmipci *cm) {}
 
 
 static struct pci_device_id snd_cmipci_ids[] = {
-       {PCI_VENDOR_ID_CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8338A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-       {PCI_VENDOR_ID_CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8338B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-       {PCI_VENDOR_ID_CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8738, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-       {PCI_VENDOR_ID_CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8738B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-       {PCI_VENDOR_ID_AL, PCI_DEVICE_ID_CMEDIA_CM8738, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+       {PCI_VDEVICE(CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8338A), 0},
+       {PCI_VDEVICE(CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8338B), 0},
+       {PCI_VDEVICE(CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8738), 0},
+       {PCI_VDEVICE(CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8738B), 0},
+       {PCI_VDEVICE(AL, PCI_DEVICE_ID_CMEDIA_CM8738), 0},
        {0,},
 };
 
index f6286f8..e2e0359 100644 (file)
@@ -495,7 +495,7 @@ struct cs4281 {
 static irqreturn_t snd_cs4281_interrupt(int irq, void *dev_id);
 
 static struct pci_device_id snd_cs4281_ids[] = {
-       { 0x1013, 0x6005, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, },   /* CS4281 */
+       { PCI_VDEVICE(CIRRUS, 0x6005), 0, },    /* CS4281 */
        { 0, }
 };
 
index c9b3e3d..033aec4 100644 (file)
@@ -65,9 +65,9 @@ module_param_array(mmap_valid, bool, NULL, 0444);
 MODULE_PARM_DESC(mmap_valid, "Support OSS mmap.");
 
 static struct pci_device_id snd_cs46xx_ids[] = {
-        { 0x1013, 0x6001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, },   /* CS4280 */
-        { 0x1013, 0x6003, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, },   /* CS4612 */
-        { 0x1013, 0x6004, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, },   /* CS4615 */
+       { PCI_VDEVICE(CIRRUS, 0x6001), 0, },   /* CS4280 */
+       { PCI_VDEVICE(CIRRUS, 0x6003), 0, },   /* CS4612 */
+       { PCI_VDEVICE(CIRRUS, 0x6004), 0, },   /* CS4615 */
        { 0, }
 };
 
index c7f3b99..168af67 100644 (file)
@@ -77,9 +77,9 @@ MODULE_PARM_DESC(subsystem, "Force card subsystem model.");
  * Class 0401: 1102:0008 (rev 00) Subsystem: 1102:1001 -> Audigy2 Value  Model:SB0400
  */
 static struct pci_device_id snd_emu10k1_ids[] = {
-       { 0x1102, 0x0002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },    /* EMU10K1 */
-       { 0x1102, 0x0004, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 },    /* Audigy */
-       { 0x1102, 0x0008, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 },    /* Audigy 2 Value SB0400 */
+       { PCI_VDEVICE(CREATIVE, 0x0002), 0 },   /* EMU10K1 */
+       { PCI_VDEVICE(CREATIVE, 0x0004), 1 },   /* Audigy */
+       { PCI_VDEVICE(CREATIVE, 0x0008), 1 },   /* Audigy 2 Value SB0400 */
        { 0, }
 };
 
index 4d3ad79..36e08bd 100644 (file)
@@ -1607,7 +1607,7 @@ static void __devexit snd_emu10k1x_remove(struct pci_dev *pci)
 
 // PCI IDs
 static struct pci_device_id snd_emu10k1x_ids[] = {
-       { 0x1102, 0x0006, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },    /* Dell OEM version (EMU10K1) */
+       { PCI_VDEVICE(CREATIVE, 0x0006), 0 },   /* Dell OEM version (EMU10K1) */
        { 0, }
 };
 MODULE_DEVICE_TABLE(pci, snd_emu10k1x_ids);
index 18f4d1e..2b82c5c 100644 (file)
@@ -445,12 +445,12 @@ static irqreturn_t snd_audiopci_interrupt(int irq, void *dev_id);
 
 static struct pci_device_id snd_audiopci_ids[] = {
 #ifdef CHIP1370
-       { 0x1274, 0x5000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, },   /* ES1370 */
+       { PCI_VDEVICE(ENSONIQ, 0x5000), 0, },   /* ES1370 */
 #endif
 #ifdef CHIP1371
-       { 0x1274, 0x1371, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, },   /* ES1371 */
-       { 0x1274, 0x5880, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, },   /* ES1373 - CT5880 */
-       { 0x1102, 0x8938, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, },   /* Ectiva EV1938 */
+       { PCI_VDEVICE(ENSONIQ, 0x1371), 0, },   /* ES1371 */
+       { PCI_VDEVICE(ENSONIQ, 0x5880), 0, },   /* ES1373 - CT5880 */
+       { PCI_VDEVICE(ECTIVA, 0x8938), 0, },    /* Ectiva EV1938 */
 #endif
        { 0, }
 };
index fbd2ac0..820318e 100644 (file)
@@ -244,7 +244,7 @@ struct es1938 {
 static irqreturn_t snd_es1938_interrupt(int irq, void *dev_id);
 
 static struct pci_device_id snd_es1938_ids[] = {
-        { 0x125d, 0x1969, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, },   /* Solo-1 */
+       { PCI_VDEVICE(ESS, 0x1969), 0, },   /* Solo-1 */
        { 0, }
 };
 
index 462e2ce..26d255d 100644 (file)
@@ -3470,10 +3470,16 @@ int snd_hda_multi_out_analog_open(struct hda_codec *codec,
                }
                mutex_lock(&codec->spdif_mutex);
                if (mout->share_spdif) {
-                       runtime->hw.rates &= mout->spdif_rates;
-                       runtime->hw.formats &= mout->spdif_formats;
-                       if (mout->spdif_maxbps < hinfo->maxbps)
-                               hinfo->maxbps = mout->spdif_maxbps;
+                       if ((runtime->hw.rates & mout->spdif_rates) &&
+                           (runtime->hw.formats & mout->spdif_formats)) {
+                               runtime->hw.rates &= mout->spdif_rates;
+                               runtime->hw.formats &= mout->spdif_formats;
+                               if (mout->spdif_maxbps < hinfo->maxbps)
+                                       hinfo->maxbps = mout->spdif_maxbps;
+                       } else {
+                               mout->share_spdif = 0;
+                               /* FIXME: need notify? */
+                       }
                }
                mutex_unlock(&codec->spdif_mutex);
        }
index 4e9ea70..1877d95 100644 (file)
@@ -1454,6 +1454,7 @@ static int azx_pcm_open(struct snd_pcm_substream *substream)
                mutex_unlock(&chip->open_mutex);
                return err;
        }
+       snd_pcm_limit_hw_rates(runtime);
        spin_lock_irqsave(&chip->reg_lock, flags);
        azx_dev->substream = substream;
        azx_dev->running = 0;
@@ -1463,6 +1464,12 @@ static int azx_pcm_open(struct snd_pcm_substream *substream)
        snd_pcm_set_sync(substream);
        mutex_unlock(&chip->open_mutex);
 
+       if (snd_BUG_ON(!runtime->hw.channels_min || !runtime->hw.channels_max))
+               return -EINVAL;
+       if (snd_BUG_ON(!runtime->hw.formats))
+               return -EINVAL;
+       if (snd_BUG_ON(!runtime->hw.rates))
+               return -EINVAL;
        return 0;
 }
 
index 84cc49c..be7d25f 100644 (file)
@@ -72,6 +72,7 @@ struct ad198x_spec {
        hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
 
        unsigned int jack_present :1;
+       unsigned int inv_jack_detect:1;
 
 #ifdef CONFIG_SND_HDA_POWER_SAVE
        struct hda_loopback_check loopback;
@@ -669,39 +670,13 @@ static struct hda_input_mux ad1986a_automic_capture_source = {
        },
 };
 
-static struct snd_kcontrol_new ad1986a_laptop_eapd_mixers[] = {
+static struct snd_kcontrol_new ad1986a_laptop_master_mixers[] = {
        HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol),
        HDA_BIND_SW("Master Playback Switch", &ad1986a_laptop_master_sw),
-       HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x17, 0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x17, 0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Mic Boost", 0x0f, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_OUTPUT),
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "Capture Source",
-               .info = ad198x_mux_enum_info,
-               .get = ad198x_mux_enum_get,
-               .put = ad198x_mux_enum_put,
-       },
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "External Amplifier",
-               .info = ad198x_eapd_info,
-               .get = ad198x_eapd_get,
-               .put = ad198x_eapd_put,
-               .private_value = 0x1b | (1 << 8), /* port-D, inversed */
-       },
        { } /* end */
 };
 
-static struct snd_kcontrol_new ad1986a_samsung_mixers[] = {
-       HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol),
-       HDA_BIND_SW("Master Playback Switch", &ad1986a_laptop_master_sw),
+static struct snd_kcontrol_new ad1986a_laptop_eapd_mixers[] = {
        HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT),
        HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT),
        HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT),
@@ -727,6 +702,12 @@ static struct snd_kcontrol_new ad1986a_samsung_mixers[] = {
        { } /* end */
 };
 
+static struct snd_kcontrol_new ad1986a_laptop_intmic_mixers[] = {
+       HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x17, 0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x17, 0, HDA_OUTPUT),
+       { } /* end */
+};
+
 /* re-connect the mic boost input according to the jack sensing */
 static void ad1986a_automic(struct hda_codec *codec)
 {
@@ -776,8 +757,9 @@ static void ad1986a_hp_automute(struct hda_codec *codec)
        unsigned int present;
 
        present = snd_hda_codec_read(codec, 0x1a, 0, AC_VERB_GET_PIN_SENSE, 0);
-       /* Lenovo N100 seems to report the reversed bit for HP jack-sensing */
-       spec->jack_present = !(present & 0x80000000);
+       spec->jack_present = !!(present & 0x80000000);
+       if (spec->inv_jack_detect)
+               spec->jack_present = !spec->jack_present;
        ad1986a_update_hp(codec);
 }
 
@@ -816,7 +798,7 @@ static int ad1986a_hp_master_sw_put(struct snd_kcontrol *kcontrol,
        return change;
 }
 
-static struct snd_kcontrol_new ad1986a_laptop_automute_mixers[] = {
+static struct snd_kcontrol_new ad1986a_automute_master_mixers[] = {
        HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol),
        {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
@@ -826,33 +808,10 @@ static struct snd_kcontrol_new ad1986a_laptop_automute_mixers[] = {
                .put = ad1986a_hp_master_sw_put,
                .private_value = HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT),
        },
-       HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x17, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x17, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Mic Boost", 0x0f, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_OUTPUT),
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "Capture Source",
-               .info = ad198x_mux_enum_info,
-               .get = ad198x_mux_enum_get,
-               .put = ad198x_mux_enum_put,
-       },
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "External Amplifier",
-               .info = ad198x_eapd_info,
-               .get = ad198x_eapd_get,
-               .put = ad198x_eapd_put,
-               .private_value = 0x1b | (1 << 8), /* port-D, inversed */
-       },
        { } /* end */
 };
 
+
 /*
  * initialization verbs
  */
@@ -981,6 +940,27 @@ static struct hda_verb ad1986a_hp_init_verbs[] = {
        {}
 };
 
+static void ad1986a_samsung_p50_unsol_event(struct hda_codec *codec,
+                                           unsigned int res)
+{
+       switch (res >> 26) {
+       case AD1986A_HP_EVENT:
+               ad1986a_hp_automute(codec);
+               break;
+       case AD1986A_MIC_EVENT:
+               ad1986a_automic(codec);
+               break;
+       }
+}
+
+static int ad1986a_samsung_p50_init(struct hda_codec *codec)
+{
+       ad198x_init(codec);
+       ad1986a_hp_automute(codec);
+       ad1986a_automic(codec);
+       return 0;
+}
+
 
 /* models */
 enum {
@@ -991,6 +971,7 @@ enum {
        AD1986A_LAPTOP_AUTOMUTE,
        AD1986A_ULTRA,
        AD1986A_SAMSUNG,
+       AD1986A_SAMSUNG_P50,
        AD1986A_MODELS
 };
 
@@ -1002,6 +983,7 @@ static const char *ad1986a_models[AD1986A_MODELS] = {
        [AD1986A_LAPTOP_AUTOMUTE] = "laptop-automute",
        [AD1986A_ULTRA]         = "ultra",
        [AD1986A_SAMSUNG]       = "samsung",
+       [AD1986A_SAMSUNG_P50]   = "samsung-p50",
 };
 
 static struct snd_pci_quirk ad1986a_cfg_tbl[] = {
@@ -1024,6 +1006,7 @@ static struct snd_pci_quirk ad1986a_cfg_tbl[] = {
        SND_PCI_QUIRK(0x1179, 0xff40, "Toshiba", AD1986A_LAPTOP_EAPD),
        SND_PCI_QUIRK(0x144d, 0xb03c, "Samsung R55", AD1986A_3STACK),
        SND_PCI_QUIRK(0x144d, 0xc01e, "FSC V2060", AD1986A_LAPTOP),
+       SND_PCI_QUIRK(0x144d, 0xc024, "Samsung P50", AD1986A_SAMSUNG_P50),
        SND_PCI_QUIRK(0x144d, 0xc027, "Samsung Q1", AD1986A_ULTRA),
        SND_PCI_QUIRK_MASK(0x144d, 0xff00, 0xc000, "Samsung", AD1986A_SAMSUNG),
        SND_PCI_QUIRK(0x144d, 0xc504, "Samsung Q35", AD1986A_3STACK),
@@ -1111,7 +1094,10 @@ static int patch_ad1986a(struct hda_codec *codec)
                spec->multiout.dac_nids = ad1986a_laptop_dac_nids;
                break;
        case AD1986A_LAPTOP_EAPD:
-               spec->mixers[0] = ad1986a_laptop_eapd_mixers;
+               spec->num_mixers = 3;
+               spec->mixers[0] = ad1986a_laptop_master_mixers;
+               spec->mixers[1] = ad1986a_laptop_eapd_mixers;
+               spec->mixers[2] = ad1986a_laptop_intmic_mixers;
                spec->num_init_verbs = 2;
                spec->init_verbs[1] = ad1986a_eapd_init_verbs;
                spec->multiout.max_channels = 2;
@@ -1122,7 +1108,9 @@ static int patch_ad1986a(struct hda_codec *codec)
                spec->input_mux = &ad1986a_laptop_eapd_capture_source;
                break;
        case AD1986A_SAMSUNG:
-               spec->mixers[0] = ad1986a_samsung_mixers;
+               spec->num_mixers = 2;
+               spec->mixers[0] = ad1986a_laptop_master_mixers;
+               spec->mixers[1] = ad1986a_laptop_eapd_mixers;
                spec->num_init_verbs = 3;
                spec->init_verbs[1] = ad1986a_eapd_init_verbs;
                spec->init_verbs[2] = ad1986a_automic_verbs;
@@ -1135,8 +1123,28 @@ static int patch_ad1986a(struct hda_codec *codec)
                codec->patch_ops.unsol_event = ad1986a_automic_unsol_event;
                codec->patch_ops.init = ad1986a_automic_init;
                break;
+       case AD1986A_SAMSUNG_P50:
+               spec->num_mixers = 2;
+               spec->mixers[0] = ad1986a_automute_master_mixers;
+               spec->mixers[1] = ad1986a_laptop_eapd_mixers;
+               spec->num_init_verbs = 4;
+               spec->init_verbs[1] = ad1986a_eapd_init_verbs;
+               spec->init_verbs[2] = ad1986a_automic_verbs;
+               spec->init_verbs[3] = ad1986a_hp_init_verbs;
+               spec->multiout.max_channels = 2;
+               spec->multiout.num_dacs = 1;
+               spec->multiout.dac_nids = ad1986a_laptop_dac_nids;
+               if (!is_jack_available(codec, 0x25))
+                       spec->multiout.dig_out_nid = 0;
+               spec->input_mux = &ad1986a_automic_capture_source;
+               codec->patch_ops.unsol_event = ad1986a_samsung_p50_unsol_event;
+               codec->patch_ops.init = ad1986a_samsung_p50_init;
+               break;
        case AD1986A_LAPTOP_AUTOMUTE:
-               spec->mixers[0] = ad1986a_laptop_automute_mixers;
+               spec->num_mixers = 3;
+               spec->mixers[0] = ad1986a_automute_master_mixers;
+               spec->mixers[1] = ad1986a_laptop_eapd_mixers;
+               spec->mixers[2] = ad1986a_laptop_intmic_mixers;
                spec->num_init_verbs = 3;
                spec->init_verbs[1] = ad1986a_eapd_init_verbs;
                spec->init_verbs[2] = ad1986a_hp_init_verbs;
@@ -1148,6 +1156,10 @@ static int patch_ad1986a(struct hda_codec *codec)
                spec->input_mux = &ad1986a_laptop_eapd_capture_source;
                codec->patch_ops.unsol_event = ad1986a_hp_unsol_event;
                codec->patch_ops.init = ad1986a_hp_init;
+               /* Lenovo N100 seems to report the reversed bit
+                * for HP jack-sensing
+                */
+               spec->inv_jack_detect = 1;
                break;
        case AD1986A_ULTRA:
                spec->mixers[0] = ad1986a_laptop_eapd_mixers;
@@ -3734,9 +3746,30 @@ static struct snd_kcontrol_new ad1884a_laptop_mixers[] = {
        { } /* end */
 };
 
+static int ad1884a_mobile_master_sw_put(struct snd_kcontrol *kcontrol,
+                                       struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       int ret = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol);
+       int mute = (!ucontrol->value.integer.value[0] &&
+                   !ucontrol->value.integer.value[1]);
+       /* toggle GPIO1 according to the mute state */
+       snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
+                           mute ? 0x02 : 0x0);
+       return ret;
+}
+
 static struct snd_kcontrol_new ad1884a_mobile_mixers[] = {
        HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),
+       /*HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),*/
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Master Playback Switch",
+               .info = snd_hda_mixer_amp_switch_info,
+               .get = snd_hda_mixer_amp_switch_get,
+               .put = ad1884a_mobile_master_sw_put,
+               .private_value = HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
+       },
        HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT),
        HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT),
        HDA_CODEC_VOLUME("Mic Capture Volume", 0x14, 0x0, HDA_INPUT),
@@ -3857,6 +3890,10 @@ static struct hda_verb ad1884a_mobile_verbs[] = {
        /* unsolicited event for pin-sense */
        {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT},
        {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_MIC_EVENT},
+       /* allow to touch GPIO1 (for mute control) */
+       {0x01, AC_VERB_SET_GPIO_MASK, 0x02},
+       {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02},
+       {0x01, AC_VERB_SET_GPIO_DATA, 0x02}, /* first muted */
        { } /* end */
 };
 
@@ -3966,6 +4003,7 @@ static struct snd_pci_quirk ad1884a_cfg_tbl[] = {
        SND_PCI_QUIRK(0x103c, 0x3037, "HP 2230s", AD1884A_LAPTOP),
        SND_PCI_QUIRK(0x103c, 0x3056, "HP", AD1884A_MOBILE),
        SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x3070, "HP", AD1884A_MOBILE),
+       SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x30d0, "HP laptop", AD1884A_LAPTOP),
        SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x30e0, "HP laptop", AD1884A_LAPTOP),
        SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x3600, "HP laptop", AD1884A_LAPTOP),
        SND_PCI_QUIRK(0x17aa, 0x20ac, "Thinkpad X300", AD1884A_THINKPAD),
index 392d108..019ca7c 100644 (file)
@@ -510,7 +510,7 @@ static int ca0110_parse_auto_config(struct hda_codec *codec)
 }
 
 
-int patch_ca0110(struct hda_codec *codec)
+static int patch_ca0110(struct hda_codec *codec)
 {
        struct ca0110_spec *spec;
        int err;
index 3345331..e661b21 100644 (file)
@@ -945,12 +945,13 @@ static void alc_fix_pll_init(struct hda_codec *codec, hda_nid_t nid,
 static void alc_automute_pin(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
-       unsigned int present;
+       unsigned int present, pincap;
        unsigned int nid = spec->autocfg.hp_pins[0];
        int i;
 
-       /* need to execute and sync at first */
-       snd_hda_codec_read(codec, nid, 0, AC_VERB_SET_PIN_SENSE, 0);
+       pincap = snd_hda_query_pin_caps(codec, nid);
+       if (pincap & AC_PINCAP_TRIG_REQ) /* need trigger? */
+               snd_hda_codec_read(codec, nid, 0, AC_VERB_SET_PIN_SENSE, 0);
        present = snd_hda_codec_read(codec, nid, 0,
                                     AC_VERB_GET_PIN_SENSE, 0);
        spec->jack_present = (present & AC_PINSENSE_PRESENCE) != 0;
@@ -1392,7 +1393,7 @@ static struct hda_verb alc888_fujitsu_xa3530_verbs[] = {
 static void alc_automute_amp(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
-       unsigned int val, mute;
+       unsigned int val, mute, pincap;
        hda_nid_t nid;
        int i;
 
@@ -1401,6 +1402,10 @@ static void alc_automute_amp(struct hda_codec *codec)
                nid = spec->autocfg.hp_pins[i];
                if (!nid)
                        break;
+               pincap = snd_hda_query_pin_caps(codec, nid);
+               if (pincap & AC_PINCAP_TRIG_REQ) /* need trigger? */
+                       snd_hda_codec_read(codec, nid, 0,
+                                          AC_VERB_SET_PIN_SENSE, 0);
                val = snd_hda_codec_read(codec, nid, 0,
                                         AC_VERB_GET_PIN_SENSE, 0);
                if (val & AC_PINSENSE_PRESENCE) {
@@ -1471,6 +1476,10 @@ static struct hda_verb alc888_acer_aspire_4930g_verbs[] = {
 static struct hda_verb alc888_acer_aspire_6530g_verbs[] = {
 /* Bias voltage on for external mic port */
        {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN | PIN_VREF80},
+/* Front Mic: set to PIN_IN (empty by default) */
+       {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+/* Unselect Front Mic by default in input mixer 3 */
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0xb)},
 /* Enable unsolicited event for HP jack */
        {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
 /* Enable speaker output */
@@ -1560,18 +1569,22 @@ static struct hda_input_mux alc888_2_capture_sources[2] = {
 static struct hda_input_mux alc888_acer_aspire_6530_sources[2] = {
        /* Interal mic only available on one ADC */
        {
-               .num_items = 3,
+               .num_items = 5,
                .items = {
                        { "Ext Mic", 0x0 },
+                       { "Line In", 0x2 },
                        { "CD", 0x4 },
+                       { "Input Mix", 0xa },
                        { "Int Mic", 0xb },
                },
        },
        {
-               .num_items = 2,
+               .num_items = 4,
                .items = {
                        { "Ext Mic", 0x0 },
+                       { "Line In", 0x2 },
                        { "CD", 0x4 },
+                       { "Input Mix", 0xa },
                },
        }
 };
@@ -1639,6 +1652,17 @@ static void alc888_acer_aspire_4930g_init_hook(struct hda_codec *codec)
        alc_automute_amp(codec);
 }
 
+static void alc888_acer_aspire_6530g_init_hook(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+
+       spec->autocfg.hp_pins[0] = 0x15;
+       spec->autocfg.speaker_pins[0] = 0x14;
+       spec->autocfg.speaker_pins[1] = 0x16;
+       spec->autocfg.speaker_pins[2] = 0x17;
+       alc_automute_amp(codec);
+}
+
 static void alc889_acer_aspire_8930g_init_hook(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
@@ -8189,6 +8213,8 @@ static struct snd_kcontrol_new alc888_acer_aspire_6530_mixer[] = {
        HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
        HDA_CODEC_VOLUME("LFE Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
        HDA_BIND_MUTE("LFE Playback Switch", 0x0f, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
        HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
        HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
        HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
@@ -9064,7 +9090,7 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = {
        SND_PCI_QUIRK(0x1025, 0x0157, "Acer X3200", ALC883_AUTO),
        SND_PCI_QUIRK(0x1025, 0x0158, "Acer AX1700-U3700A", ALC883_AUTO),
        SND_PCI_QUIRK(0x1025, 0x015e, "Acer Aspire 6930G",
-               ALC888_ACER_ASPIRE_4930G),
+               ALC888_ACER_ASPIRE_6530G),
        SND_PCI_QUIRK(0x1025, 0x0166, "Acer Aspire 6530G",
                ALC888_ACER_ASPIRE_6530G),
        /* default Acer -- disabled as it causes more problems.
@@ -9317,7 +9343,7 @@ static struct alc_config_preset alc883_presets[] = {
                        ARRAY_SIZE(alc888_2_capture_sources),
                .input_mux = alc888_acer_aspire_6530_sources,
                .unsol_event = alc_automute_amp_unsol_event,
-               .init_hook = alc888_acer_aspire_4930g_init_hook,
+               .init_hook = alc888_acer_aspire_6530g_init_hook,
        },
        [ALC888_ACER_ASPIRE_8930G] = {
                .mixers = { alc888_base_mixer,
@@ -12437,6 +12463,8 @@ static int alc268_parse_auto_config(struct hda_codec *codec)
        if (err < 0)
                return err;
 
+       alc_ssid_check(codec, 0x15, 0x1b, 0x14);
+
        return 1;
 }
 
@@ -12848,20 +12876,11 @@ static struct snd_kcontrol_new alc269_lifebook_mixer[] = {
        { }
 };
 
-/* bind volumes of both NID 0x0c and 0x0d */
-static struct hda_bind_ctls alc269_epc_bind_vol = {
-       .ops = &snd_hda_bind_vol,
-       .values = {
-               HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
-               HDA_COMPOSE_AMP_VAL(0x03, 3, 0, HDA_OUTPUT),
-               0
-       },
-};
-
 static struct snd_kcontrol_new alc269_eeepc_mixer[] = {
-       HDA_CODEC_MUTE("iSpeaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
-       HDA_BIND_VOL("LineOut Playback Volume", &alc269_epc_bind_vol),
-       HDA_CODEC_MUTE("LineOut Playback Switch", 0x15, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
        { } /* end */
 };
 
@@ -12874,12 +12893,7 @@ static struct snd_kcontrol_new alc269_epc_capture_mixer[] = {
 };
 
 /* FSC amilo */
-static struct snd_kcontrol_new alc269_fujitsu_mixer[] = {
-       HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
-       HDA_BIND_VOL("PCM Playback Volume", &alc269_epc_bind_vol),
-       { } /* end */
-};
+#define alc269_fujitsu_mixer   alc269_eeepc_mixer
 
 static struct hda_verb alc269_quanta_fl1_verbs[] = {
        {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
@@ -13345,6 +13359,8 @@ static int alc269_parse_auto_config(struct hda_codec *codec)
        if (!spec->cap_mixer && !spec->no_analog)
                set_capture_mixer(spec);
 
+       alc_ssid_check(codec, 0x15, 0x1b, 0x14);
+
        return 1;
 }
 
index 0d0cdbd..cecf1ff 100644 (file)
@@ -107,7 +107,7 @@ MODULE_PARM_DESC(dxr_enable, "Enable DXR support for Terratec DMX6FIRE.");
 
 
 static const struct pci_device_id snd_ice1712_ids[] = {
-       { PCI_VENDOR_ID_ICE, PCI_DEVICE_ID_ICE_1712, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },   /* ICE1712 */
+       { PCI_VDEVICE(ICE, PCI_DEVICE_ID_ICE_1712), 0 },   /* ICE1712 */
        { 0, }
 };
 
index 36ade77..cc84a83 100644 (file)
@@ -93,7 +93,7 @@ MODULE_PARM_DESC(model, "Use the given board model.");
 
 /* Both VT1720 and VT1724 have the same PCI IDs */
 static const struct pci_device_id snd_vt1724_ids[] = {
-       { PCI_VENDOR_ID_ICE, PCI_DEVICE_ID_VT1724, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+       { PCI_VDEVICE(ICE, PCI_DEVICE_ID_VT1724), 0 },
        { 0, }
 };
 
index 8aa5687..171ada5 100644 (file)
@@ -421,29 +421,29 @@ struct intel8x0 {
 };
 
 static struct pci_device_id snd_intel8x0_ids[] = {
-       { 0x8086, 0x2415, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL }, /* 82801AA */
-       { 0x8086, 0x2425, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL }, /* 82901AB */
-       { 0x8086, 0x2445, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL }, /* 82801BA */
-       { 0x8086, 0x2485, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL }, /* ICH3 */
-       { 0x8086, 0x24c5, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL_ICH4 }, /* ICH4 */
-       { 0x8086, 0x24d5, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL_ICH4 }, /* ICH5 */
-       { 0x8086, 0x25a6, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL_ICH4 }, /* ESB */
-       { 0x8086, 0x266e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL_ICH4 }, /* ICH6 */
-       { 0x8086, 0x27de, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL_ICH4 }, /* ICH7 */
-       { 0x8086, 0x2698, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL_ICH4 }, /* ESB2 */
-       { 0x8086, 0x7195, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL }, /* 440MX */
-       { 0x1039, 0x7012, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_SIS },   /* SI7012 */
-       { 0x10de, 0x01b1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_NFORCE },        /* NFORCE */
-       { 0x10de, 0x003a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_NFORCE },        /* MCP04 */
-       { 0x10de, 0x006a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_NFORCE },        /* NFORCE2 */
-       { 0x10de, 0x0059, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_NFORCE },        /* CK804 */
-       { 0x10de, 0x008a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_NFORCE },        /* CK8 */
-       { 0x10de, 0x00da, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_NFORCE },        /* NFORCE3 */
-       { 0x10de, 0x00ea, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_NFORCE },        /* CK8S */
-       { 0x10de, 0x026b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_NFORCE },        /* MCP51 */
-       { 0x1022, 0x746d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL }, /* AMD8111 */
-       { 0x1022, 0x7445, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL }, /* AMD768 */
-       { 0x10b9, 0x5455, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_ALI },   /* Ali5455 */
+       { PCI_VDEVICE(INTEL, 0x2415), DEVICE_INTEL },   /* 82801AA */
+       { PCI_VDEVICE(INTEL, 0x2425), DEVICE_INTEL },   /* 82901AB */
+       { PCI_VDEVICE(INTEL, 0x2445), DEVICE_INTEL },   /* 82801BA */
+       { PCI_VDEVICE(INTEL, 0x2485), DEVICE_INTEL },   /* ICH3 */
+       { PCI_VDEVICE(INTEL, 0x24c5), DEVICE_INTEL_ICH4 }, /* ICH4 */
+       { PCI_VDEVICE(INTEL, 0x24d5), DEVICE_INTEL_ICH4 }, /* ICH5 */
+       { PCI_VDEVICE(INTEL, 0x25a6), DEVICE_INTEL_ICH4 }, /* ESB */
+       { PCI_VDEVICE(INTEL, 0x266e), DEVICE_INTEL_ICH4 }, /* ICH6 */
+       { PCI_VDEVICE(INTEL, 0x27de), DEVICE_INTEL_ICH4 }, /* ICH7 */
+       { PCI_VDEVICE(INTEL, 0x2698), DEVICE_INTEL_ICH4 }, /* ESB2 */
+       { PCI_VDEVICE(INTEL, 0x7195), DEVICE_INTEL },   /* 440MX */
+       { PCI_VDEVICE(SI, 0x7012), DEVICE_SIS },        /* SI7012 */
+       { PCI_VDEVICE(NVIDIA, 0x01b1), DEVICE_NFORCE }, /* NFORCE */
+       { PCI_VDEVICE(NVIDIA, 0x003a), DEVICE_NFORCE }, /* MCP04 */
+       { PCI_VDEVICE(NVIDIA, 0x006a), DEVICE_NFORCE }, /* NFORCE2 */
+       { PCI_VDEVICE(NVIDIA, 0x0059), DEVICE_NFORCE }, /* CK804 */
+       { PCI_VDEVICE(NVIDIA, 0x008a), DEVICE_NFORCE }, /* CK8 */
+       { PCI_VDEVICE(NVIDIA, 0x00da), DEVICE_NFORCE }, /* NFORCE3 */
+       { PCI_VDEVICE(NVIDIA, 0x00ea), DEVICE_NFORCE }, /* CK8S */
+       { PCI_VDEVICE(NVIDIA, 0x026b), DEVICE_NFORCE }, /* MCP51 */
+       { PCI_VDEVICE(AMD, 0x746d), DEVICE_INTEL },     /* AMD8111 */
+       { PCI_VDEVICE(AMD, 0x7445), DEVICE_INTEL },     /* AMD768 */
+       { PCI_VDEVICE(AL, 0x5455), DEVICE_ALI },   /* Ali5455 */
        { 0, }
 };
 
index 6ec0fc5..9e7d12e 100644 (file)
@@ -220,24 +220,24 @@ struct intel8x0m {
 };
 
 static struct pci_device_id snd_intel8x0m_ids[] = {
-       { 0x8086, 0x2416, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL }, /* 82801AA */
-       { 0x8086, 0x2426, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL }, /* 82901AB */
-       { 0x8086, 0x2446, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL }, /* 82801BA */
-       { 0x8086, 0x2486, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL }, /* ICH3 */
-       { 0x8086, 0x24c6, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL }, /* ICH4 */
-       { 0x8086, 0x24d6, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL }, /* ICH5 */
-       { 0x8086, 0x266d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL }, /* ICH6 */
-       { 0x8086, 0x27dd, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL }, /* ICH7 */
-       { 0x8086, 0x7196, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL }, /* 440MX */
-       { 0x1022, 0x7446, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL }, /* AMD768 */
-       { 0x1039, 0x7013, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_SIS },   /* SI7013 */
-       { 0x10de, 0x01c1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_NFORCE }, /* NFORCE */
-       { 0x10de, 0x0069, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_NFORCE }, /* NFORCE2 */
-       { 0x10de, 0x0089, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_NFORCE }, /* NFORCE2s */
-       { 0x10de, 0x00d9, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_NFORCE }, /* NFORCE3 */
+       { PCI_VDEVICE(INTEL, 0x2416), DEVICE_INTEL },   /* 82801AA */
+       { PCI_VDEVICE(INTEL, 0x2426), DEVICE_INTEL },   /* 82901AB */
+       { PCI_VDEVICE(INTEL, 0x2446), DEVICE_INTEL },   /* 82801BA */
+       { PCI_VDEVICE(INTEL, 0x2486), DEVICE_INTEL },   /* ICH3 */
+       { PCI_VDEVICE(INTEL, 0x24c6), DEVICE_INTEL }, /* ICH4 */
+       { PCI_VDEVICE(INTEL, 0x24d6), DEVICE_INTEL }, /* ICH5 */
+       { PCI_VDEVICE(INTEL, 0x266d), DEVICE_INTEL },   /* ICH6 */
+       { PCI_VDEVICE(INTEL, 0x27dd), DEVICE_INTEL },   /* ICH7 */
+       { PCI_VDEVICE(INTEL, 0x7196), DEVICE_INTEL },   /* 440MX */
+       { PCI_VDEVICE(AMD, 0x7446), DEVICE_INTEL },     /* AMD768 */
+       { PCI_VDEVICE(SI, 0x7013), DEVICE_SIS },        /* SI7013 */
+       { PCI_VDEVICE(NVIDIA, 0x01c1), DEVICE_NFORCE }, /* NFORCE */
+       { PCI_VDEVICE(NVIDIA, 0x0069), DEVICE_NFORCE }, /* NFORCE2 */
+       { PCI_VDEVICE(NVIDIA, 0x0089), DEVICE_NFORCE }, /* NFORCE2s */
+       { PCI_VDEVICE(NVIDIA, 0x00d9), DEVICE_NFORCE }, /* NFORCE3 */
 #if 0
-       { 0x1022, 0x746d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL }, /* AMD8111 */
-       { 0x10b9, 0x5455, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_ALI },   /* Ali5455 */
+       { PCI_VDEVICE(AMD, 0x746d), DEVICE_INTEL },     /* AMD8111 */
+       { PCI_VDEVICE(AL, 0x5455), DEVICE_ALI },   /* Ali5455 */
 #endif
        { 0, }
 };
index 18da2ef..11b8c65 100644 (file)
@@ -654,13 +654,12 @@ static int __devinit lx_init_ethersound_config(struct lx6464es *chip)
        int i;
        u32 orig_conf_es = lx_dsp_reg_read(chip, eReg_CONFES);
 
-       u32 default_conf_es = (64 << IOCR_OUTPUTS_OFFSET) |
+       /* configure 64 io channels */
+       u32 conf_es = (orig_conf_es & CONFES_READ_PART_MASK) |
                (64 << IOCR_INPUTS_OFFSET) |
+               (64 << IOCR_OUTPUTS_OFFSET) |
                (FREQ_RATIO_SINGLE_MODE << FREQ_RATIO_OFFSET);
 
-       u32 conf_es = (orig_conf_es & CONFES_READ_PART_MASK)
-               | (default_conf_es & CONFES_WRITE_PART_MASK);
-
        snd_printdd("->lx_init_ethersound\n");
 
        chip->freq_ratio = FREQ_RATIO_SINGLE_MODE;
index 82bc5b9..a83d196 100644 (file)
@@ -61,7 +61,7 @@ MODULE_PARM_DESC(enable, "Enable Digigram " CARD_NAME " soundcard.");
  */
 
 static struct pci_device_id snd_mixart_ids[] = {
-       { 0x1057, 0x0003, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* MC8240 */
+       { PCI_VDEVICE(MOTOROLA, 0x0003), 0, }, /* MC8240 */
        { 0, }
 };
 
index 522a040..97a0731 100644 (file)
@@ -263,9 +263,9 @@ struct nm256 {
  * PCI ids
  */
 static struct pci_device_id snd_nm256_ids[] = {
-       {PCI_VENDOR_ID_NEOMAGIC, PCI_DEVICE_ID_NEOMAGIC_NM256AV_AUDIO, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-       {PCI_VENDOR_ID_NEOMAGIC, PCI_DEVICE_ID_NEOMAGIC_NM256ZX_AUDIO, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-       {PCI_VENDOR_ID_NEOMAGIC, PCI_DEVICE_ID_NEOMAGIC_NM256XL_PLUS_AUDIO, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+       {PCI_VDEVICE(NEOMAGIC, PCI_DEVICE_ID_NEOMAGIC_NM256AV_AUDIO), 0},
+       {PCI_VDEVICE(NEOMAGIC, PCI_DEVICE_ID_NEOMAGIC_NM256ZX_AUDIO), 0},
+       {PCI_VDEVICE(NEOMAGIC, PCI_DEVICE_ID_NEOMAGIC_NM256XL_PLUS_AUDIO), 0},
        {0,},
 };
 
index 304da16..5401c54 100644 (file)
@@ -575,8 +575,10 @@ static int ac97_switch_put(struct snd_kcontrol *ctl,
 static int ac97_volume_info(struct snd_kcontrol *ctl,
                            struct snd_ctl_elem_info *info)
 {
+       int stereo = (ctl->private_value >> 16) & 1;
+
        info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
-       info->count = 2;
+       info->count = stereo ? 2 : 1;
        info->value.integer.min = 0;
        info->value.integer.max = 0x1f;
        return 0;
@@ -587,6 +589,7 @@ static int ac97_volume_get(struct snd_kcontrol *ctl,
 {
        struct oxygen *chip = ctl->private_data;
        unsigned int codec = (ctl->private_value >> 24) & 1;
+       int stereo = (ctl->private_value >> 16) & 1;
        unsigned int index = ctl->private_value & 0xff;
        u16 reg;
 
@@ -594,7 +597,8 @@ static int ac97_volume_get(struct snd_kcontrol *ctl,
        reg = oxygen_read_ac97(chip, codec, index);
        mutex_unlock(&chip->mutex);
        value->value.integer.value[0] = 31 - (reg & 0x1f);
-       value->value.integer.value[1] = 31 - ((reg >> 8) & 0x1f);
+       if (stereo)
+               value->value.integer.value[1] = 31 - ((reg >> 8) & 0x1f);
        return 0;
 }
 
@@ -603,6 +607,7 @@ static int ac97_volume_put(struct snd_kcontrol *ctl,
 {
        struct oxygen *chip = ctl->private_data;
        unsigned int codec = (ctl->private_value >> 24) & 1;
+       int stereo = (ctl->private_value >> 16) & 1;
        unsigned int index = ctl->private_value & 0xff;
        u16 oldreg, newreg;
        int change;
@@ -612,8 +617,11 @@ static int ac97_volume_put(struct snd_kcontrol *ctl,
        newreg = oldreg;
        newreg = (newreg & ~0x1f) |
                (31 - (value->value.integer.value[0] & 0x1f));
-       newreg = (newreg & ~0x1f00) |
-               ((31 - (value->value.integer.value[0] & 0x1f)) << 8);
+       if (stereo)
+               newreg = (newreg & ~0x1f00) |
+                       ((31 - (value->value.integer.value[1] & 0x1f)) << 8);
+       else
+               newreg = (newreg & ~0x1f00) | ((newreg & 0x1f) << 8);
        change = newreg != oldreg;
        if (change)
                oxygen_write_ac97(chip, codec, index, newreg);
@@ -673,7 +681,7 @@ static int ac97_fp_rec_volume_put(struct snd_kcontrol *ctl,
                .private_value = ((codec) << 24) | ((invert) << 16) | \
                                 ((bitnr) << 8) | (index), \
        }
-#define AC97_VOLUME(xname, codec, index) { \
+#define AC97_VOLUME(xname, codec, index, stereo) { \
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
                .name = xname, \
                .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \
@@ -682,7 +690,7 @@ static int ac97_fp_rec_volume_put(struct snd_kcontrol *ctl,
                .get = ac97_volume_get, \
                .put = ac97_volume_put, \
                .tlv = { .p = ac97_db_scale, }, \
-               .private_value = ((codec) << 24) | (index), \
+               .private_value = ((codec) << 24) | ((stereo) << 16) | (index), \
        }
 
 static DECLARE_TLV_DB_SCALE(monitor_db_scale, -1000, 1000, 0);
@@ -882,18 +890,18 @@ static const struct {
 };
 
 static const struct snd_kcontrol_new ac97_controls[] = {
-       AC97_VOLUME("Mic Capture Volume", 0, AC97_MIC),
+       AC97_VOLUME("Mic Capture Volume", 0, AC97_MIC, 0),
        AC97_SWITCH("Mic Capture Switch", 0, AC97_MIC, 15, 1),
        AC97_SWITCH("Mic Boost (+20dB)", 0, AC97_MIC, 6, 0),
        AC97_SWITCH("Line Capture Switch", 0, AC97_LINE, 15, 1),
-       AC97_VOLUME("CD Capture Volume", 0, AC97_CD),
+       AC97_VOLUME("CD Capture Volume", 0, AC97_CD, 1),
        AC97_SWITCH("CD Capture Switch", 0, AC97_CD, 15, 1),
-       AC97_VOLUME("Aux Capture Volume", 0, AC97_AUX),
+       AC97_VOLUME("Aux Capture Volume", 0, AC97_AUX, 1),
        AC97_SWITCH("Aux Capture Switch", 0, AC97_AUX, 15, 1),
 };
 
 static const struct snd_kcontrol_new ac97_fp_controls[] = {
-       AC97_VOLUME("Front Panel Playback Volume", 1, AC97_HEADPHONE),
+       AC97_VOLUME("Front Panel Playback Volume", 1, AC97_HEADPHONE, 1),
        AC97_SWITCH("Front Panel Playback Switch", 1, AC97_HEADPHONE, 15, 1),
        {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
index bf971f7..6ebcb6b 100644 (file)
@@ -635,6 +635,8 @@ static void xonar_d2_resume(struct oxygen *chip)
 
 static void xonar_d1_resume(struct oxygen *chip)
 {
+       oxygen_set_bits8(chip, OXYGEN_FUNCTION, OXYGEN_FUNCTION_RESET_CODEC);
+       msleep(1);
        cs43xx_init(chip);
        xonar_enable_output(chip);
 }
index d7b966e..f977dba 100644 (file)
@@ -227,12 +227,9 @@ struct rme32 {
 };
 
 static struct pci_device_id snd_rme32_ids[] = {
-       {PCI_VENDOR_ID_XILINX_RME, PCI_DEVICE_ID_RME_DIGI32,
-        PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0,},
-       {PCI_VENDOR_ID_XILINX_RME, PCI_DEVICE_ID_RME_DIGI32_8,
-        PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0,},
-       {PCI_VENDOR_ID_XILINX_RME, PCI_DEVICE_ID_RME_DIGI32_PRO,
-        PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0,},
+       {PCI_VDEVICE(XILINX_RME, PCI_DEVICE_ID_RME_DIGI32), 0,},
+       {PCI_VDEVICE(XILINX_RME, PCI_DEVICE_ID_RME_DIGI32_8), 0,},
+       {PCI_VDEVICE(XILINX_RME, PCI_DEVICE_ID_RME_DIGI32_PRO), 0,},
        {0,}
 };
 
index 55fb1c1..2ba5c0f 100644 (file)
@@ -232,14 +232,10 @@ struct rme96 {
 };
 
 static struct pci_device_id snd_rme96_ids[] = {
-       { PCI_VENDOR_ID_XILINX, PCI_DEVICE_ID_RME_DIGI96,
-         PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, },
-       { PCI_VENDOR_ID_XILINX, PCI_DEVICE_ID_RME_DIGI96_8,
-         PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, },
-       { PCI_VENDOR_ID_XILINX, PCI_DEVICE_ID_RME_DIGI96_8_PRO,
-         PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, },
-       { PCI_VENDOR_ID_XILINX, PCI_DEVICE_ID_RME_DIGI96_8_PAD_OR_PST,
-         PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, 
+       { PCI_VDEVICE(XILINX, PCI_DEVICE_ID_RME_DIGI96), 0, },
+       { PCI_VDEVICE(XILINX, PCI_DEVICE_ID_RME_DIGI96_8), 0, },
+       { PCI_VDEVICE(XILINX, PCI_DEVICE_ID_RME_DIGI96_8_PRO), 0, },
+       { PCI_VDEVICE(XILINX, PCI_DEVICE_ID_RME_DIGI96_8_PAD_OR_PST), 0, },
        { 0, }
 };
 
index 7dc60ad..1f6406c 100644 (file)
@@ -243,7 +243,7 @@ struct sonicvibes {
 };
 
 static struct pci_device_id snd_sonic_ids[] = {
-       { 0x5333, 0xca00, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, },
+       { PCI_VDEVICE(S3, 0xca00), 0, },
         { 0, }
 };
 
index 949fcaf..acfa476 100644 (file)
@@ -402,9 +402,9 @@ struct via82xx {
 
 static struct pci_device_id snd_via82xx_ids[] = {
        /* 0x1106, 0x3058 */
-       { PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_5, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TYPE_CARD_VIA686, },     /* 686A */
+       { PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_82C686_5), TYPE_CARD_VIA686, },    /* 686A */
        /* 0x1106, 0x3059 */
-       { PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8233_5, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TYPE_CARD_VIA8233, },      /* VT8233 */
+       { PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_8233_5), TYPE_CARD_VIA8233, },     /* VT8233 */
        { 0, }
 };
 
index 0d54e35..47eb615 100644 (file)
@@ -261,7 +261,7 @@ struct via82xx_modem {
 };
 
 static struct pci_device_id snd_via82xx_modem_ids[] = {
-       { 0x1106, 0x3068, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TYPE_CARD_VIA82XX_MODEM, },
+       { PCI_VDEVICE(VIA, 0x3068), TYPE_CARD_VIA82XX_MODEM, },
        { 0, }
 };
 
index 4af6666..e6b18b9 100644 (file)
@@ -67,12 +67,12 @@ module_param_array(rear_switch, bool, NULL, 0444);
 MODULE_PARM_DESC(rear_switch, "Enable shared rear/line-in switch");
 
 static struct pci_device_id snd_ymfpci_ids[] = {
-        { 0x1073, 0x0004, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, },   /* YMF724 */
-        { 0x1073, 0x000d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, },   /* YMF724F */
-        { 0x1073, 0x000a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, },   /* YMF740 */
-        { 0x1073, 0x000c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, },   /* YMF740C */
-        { 0x1073, 0x0010, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, },   /* YMF744 */
-        { 0x1073, 0x0012, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, },   /* YMF754 */
+       { PCI_VDEVICE(YAMAHA, 0x0004), 0, },   /* YMF724 */
+       { PCI_VDEVICE(YAMAHA, 0x000d), 0, },   /* YMF724F */
+       { PCI_VDEVICE(YAMAHA, 0x000a), 0, },   /* YMF740 */
+       { PCI_VDEVICE(YAMAHA, 0x000c), 0, },   /* YMF740C */
+       { PCI_VDEVICE(YAMAHA, 0x0010), 0, },   /* YMF744 */
+       { PCI_VDEVICE(YAMAHA, 0x0012), 0, },   /* YMF754 */
        { 0, }
 };
 
index 5dbebf8..8cb65cc 100644 (file)
@@ -33,7 +33,7 @@ config SND_SOC_MPC5200_I2S
 config SND_SOC_MPC5200_AC97
        tristate "Freescale MPC5200 PSC in AC97 mode driver"
        depends on PPC_MPC52xx && PPC_BESTCOMM
-       select AC97_BUS
+       select SND_SOC_AC97_BUS
        select SND_MPC52xx_DMA
        select PPC_BESTCOMM_GEN_BD
        help
@@ -41,7 +41,7 @@ config SND_SOC_MPC5200_AC97
 
 config SND_MPC52xx_SOC_PCM030
        tristate "SoC AC97 Audio support for Phytec pcm030 and WM9712"
-       depends on PPC_MPC5200_SIMPLE && BROKEN
+       depends on PPC_MPC5200_SIMPLE
        select SND_SOC_MPC5200_AC97
        select SND_SOC_WM9712
        help
@@ -50,7 +50,7 @@ config SND_MPC52xx_SOC_PCM030
 
 config SND_MPC52xx_SOC_EFIKA
        tristate "SoC AC97 Audio support for bbplan Efika and STAC9766"
-       depends on PPC_EFIKA && BROKEN
+       depends on PPC_EFIKA
        select SND_SOC_MPC5200_AC97
        select SND_SOC_STAC9766
        help
index 6454e15..84a1950 100644 (file)
@@ -216,12 +216,15 @@ static snd_pcm_uframes_t omap_pcm_pointer(struct snd_pcm_substream *substream)
        dma_addr_t ptr;
        snd_pcm_uframes_t offset;
 
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-               ptr = omap_get_dma_src_pos(prtd->dma_ch);
-       else
+       if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
                ptr = omap_get_dma_dst_pos(prtd->dma_ch);
+               offset = bytes_to_frames(runtime, ptr - runtime->dma_addr);
+       } else if (!(cpu_is_omap1510())) {
+               ptr = omap_get_dma_src_pos(prtd->dma_ch);
+               offset = bytes_to_frames(runtime, ptr - runtime->dma_addr);
+       } else
+               offset = prtd->period_index * runtime->period_size;
 
-       offset = bytes_to_frames(runtime, ptr - runtime->dma_addr);
        if (offset >= runtime->buffer_size)
                offset = 0;
 
index 4743e26..6b8f655 100644 (file)
@@ -167,6 +167,7 @@ static int pxa2xx_i2s_hw_params(struct snd_pcm_substream *substream,
 
        BUG_ON(IS_ERR(clk_i2s));
        clk_enable(clk_i2s);
+       dai->private_data = dai;
        pxa_i2s_wait();
 
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
@@ -255,7 +256,10 @@ static void pxa2xx_i2s_shutdown(struct snd_pcm_substream *substream,
        if ((SACR1 & (SACR1_DREC | SACR1_DRPL)) == (SACR1_DREC | SACR1_DRPL)) {
                SACR0 &= ~SACR0_ENB;
                pxa_i2s_wait();
-               clk_disable(clk_i2s);
+               if (dai->private_data != NULL) {
+                       clk_disable(clk_i2s);
+                       dai->private_data = NULL;
+               }
        }
 }
 
@@ -336,6 +340,7 @@ static int pxa2xx_i2s_probe(struct platform_device *dev)
                return PTR_ERR(clk_i2s);
 
        pxa_i2s_dai.dev = &dev->dev;
+       pxa_i2s_dai.private_data = NULL;
        ret = snd_soc_register_dai(&pxa_i2s_dai);
        if (ret != 0)
                clk_put(clk_i2s);
index 12522e6..a41f8b1 100644 (file)
@@ -10,6 +10,8 @@
 #include <linux/module.h>
 #include <linux/device.h>
 #include <linux/err.h>
+#include <linux/kdev_t.h>
+#include <linux/major.h>
 #include <sound/core.h>
 
 #ifdef CONFIG_SOUND_OSS_CORE
@@ -29,6 +31,8 @@ MODULE_LICENSE("GPL");
 
 static char *sound_nodename(struct device *dev)
 {
+       if (MAJOR(dev->devt) == SOUND_MAJOR)
+               return NULL;
        return kasprintf(GFP_KERNEL, "snd/%s", dev_name(dev));
 }
 
@@ -104,7 +108,6 @@ module_exit(cleanup_soundcore);
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/sound.h>
-#include <linux/major.h>
 #include <linux/kmod.h>
 
 #define SOUND_STEP 16
index 0e5db71..de38108 100644 (file)
@@ -35,7 +35,7 @@
 #include "input.h"
 
 MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>");
-MODULE_DESCRIPTION("caiaq USB audio, version 1.3.17");
+MODULE_DESCRIPTION("caiaq USB audio, version 1.3.18");
 MODULE_LICENSE("GPL");
 MODULE_SUPPORTED_DEVICE("{{Native Instruments, RigKontrol2},"
                         "{Native Instruments, RigKontrol3},"
@@ -349,7 +349,9 @@ static void __devinit setup_card(struct snd_usb_caiaqdev *dev)
                log("Unable to set up control system (ret=%d)\n", ret);
 }
 
-static int create_card(struct usb_device* usb_dev, struct snd_card **cardp)
+static int create_card(struct usb_device *usb_dev,
+                      struct usb_interface *intf,
+                      struct snd_card **cardp)
 {
        int devnum;
        int err;
@@ -374,7 +376,7 @@ static int create_card(struct usb_device* usb_dev, struct snd_card **cardp)
        dev->chip.usb_id = USB_ID(le16_to_cpu(usb_dev->descriptor.idVendor),
                                  le16_to_cpu(usb_dev->descriptor.idProduct));
        spin_lock_init(&dev->spinlock);
-       snd_card_set_dev(card, &usb_dev->dev);
+       snd_card_set_dev(card, &intf->dev);
 
        *cardp = card;
        return 0;
@@ -461,7 +463,7 @@ static int __devinit snd_probe(struct usb_interface *intf,
        struct snd_card *card;
        struct usb_device *device = interface_to_usbdev(intf);
 
-       ret = create_card(device, &card);
+       ret = create_card(device, intf, &card);
 
        if (ret < 0)
                return ret;
index a5aae9d..fd44946 100644 (file)
@@ -514,7 +514,6 @@ static int usx2y_create_card(struct usb_device *device, struct snd_card **cardp)
                US122L(card)->chip.dev->bus->busnum,
                US122L(card)->chip.dev->devnum
                );
-       snd_card_set_dev(card, &device->dev);
        *cardp = card;
        return 0;
 }
@@ -531,6 +530,7 @@ static int us122l_usb_probe(struct usb_interface *intf,
        if (err < 0)
                return err;
 
+       snd_card_set_dev(card, &intf->dev);
        if (!us122l_create_card(card)) {
                snd_card_free(card);
                return -EINVAL;
index 5ce0da2..cb4bb83 100644 (file)
@@ -364,7 +364,6 @@ static int usX2Y_create_card(struct usb_device *device, struct snd_card **cardp)
                0,//us428(card)->usbmidi.ifnum,
                usX2Y(card)->chip.dev->bus->busnum, usX2Y(card)->chip.dev->devnum
                );
-       snd_card_set_dev(card, &device->dev);
        *cardp = card;
        return 0;
 }
@@ -388,6 +387,7 @@ static int usX2Y_usb_probe(struct usb_device *device,
        err = usX2Y_create_card(device, &card);
        if (err < 0)
                return err;
+       snd_card_set_dev(card, &intf->dev);
        if ((err = usX2Y_hwdep_new(card, device)) < 0  ||
            (err = snd_card_register(card)) < 0) {
                snd_card_free(card);
diff --git a/tools/perf/CREDITS b/tools/perf/CREDITS
new file mode 100644 (file)
index 0000000..c2ddcb3
--- /dev/null
@@ -0,0 +1,30 @@
+Most of the infrastructure that 'perf' uses here has been reused
+from the Git project, as of version:
+
+    66996ec: Sync with 1.6.2.4
+
+Here is an (incomplete!) list of main contributors to those files
+in util/* and elsewhere:
+
+ Alex Riesen
+ Christian Couder
+ Dmitry Potapov
+ Jeff King
+ Johannes Schindelin
+ Johannes Sixt
+ Junio C Hamano
+ Linus Torvalds
+ Matthias Kestenholz
+ Michal Ostrowski
+ Miklos Vajna
+ Petr Baudis
+ Pierre Habouzit
+ René Scharfe
+ Samuel Tardieu
+ Shawn O. Pearce
+ Steffen Prohaska
+ Steve Haslam
+
+Thanks guys!
+
+The full history of the files can be found in the upstream Git commits.
index 52d3fc6..8aa3f8c 100644 (file)
@@ -13,13 +13,25 @@ SYNOPSIS
 DESCRIPTION
 -----------
 This command displays the performance counter profile information recorded
-via perf report.
+via perf record.
 
 OPTIONS
 -------
 -i::
 --input=::
         Input file name. (default: perf.data)
+-d::
+--dsos=::
+       Only consider symbols in these dsos. CSV that understands
+       file://filename entries.
+-C::
+--comms=::
+       Only consider symbols in these comms. CSV that understands
+       file://filename entries.
+-S::
+--symbols=::
+       Only consider these symbols. CSV that understands
+       file://filename entries.
 
 SEE ALSO
 --------
index c368a72..0d74346 100644 (file)
@@ -8,8 +8,8 @@ perf-stat - Run a command and gather performance counter statistics
 SYNOPSIS
 --------
 [verse]
-'perf stat' [-e <EVENT> | --event=EVENT] [-l] [-a] <command>
-'perf stat' [-e <EVENT> | --event=EVENT] [-l] [-a] -- <command> [<options>]
+'perf stat' [-e <EVENT> | --event=EVENT] [-S] [-a] <command>
+'perf stat' [-e <EVENT> | --event=EVENT] [-S] [-a] -- <command> [<options>]
 
 DESCRIPTION
 -----------
@@ -40,7 +40,7 @@ OPTIONS
 -a::
         system-wide collection
 
--l::
+-S::
         scale counter values
 
 EXAMPLES
index 36d7eef..9c6d0ae 100644 (file)
@@ -290,7 +290,7 @@ LIB_FILE=libperf.a
 
 LIB_H += ../../include/linux/perf_counter.h
 LIB_H += perf.h
-LIB_H += types.h
+LIB_H += util/types.h
 LIB_H += util/list.h
 LIB_H += util/rbtree.h
 LIB_H += util/levenshtein.h
@@ -301,6 +301,7 @@ LIB_H += util/util.h
 LIB_H += util/help.h
 LIB_H += util/strbuf.h
 LIB_H += util/string.h
+LIB_H += util/strlist.h
 LIB_H += util/run-command.h
 LIB_H += util/sigchain.h
 LIB_H += util/symbol.h
@@ -322,12 +323,15 @@ LIB_OBJS += util/run-command.o
 LIB_OBJS += util/quote.o
 LIB_OBJS += util/strbuf.o
 LIB_OBJS += util/string.o
+LIB_OBJS += util/strlist.o
 LIB_OBJS += util/usage.o
 LIB_OBJS += util/wrapper.o
 LIB_OBJS += util/sigchain.o
 LIB_OBJS += util/symbol.o
 LIB_OBJS += util/color.o
 LIB_OBJS += util/pager.o
+LIB_OBJS += util/header.o
+LIB_OBJS += util/callchain.o
 
 BUILTIN_OBJS += builtin-annotate.o
 BUILTIN_OBJS += builtin-help.o
index 7e58e3a..722c0f5 100644 (file)
@@ -855,7 +855,7 @@ static unsigned long total = 0,
                     total_unknown = 0;
 
 static int
-process_overflow_event(event_t *event, unsigned long offset, unsigned long head)
+process_sample_event(event_t *event, unsigned long offset, unsigned long head)
 {
        char level;
        int show = 0;
@@ -1013,10 +1013,10 @@ process_period_event(event_t *event, unsigned long offset, unsigned long head)
 static int
 process_event(event_t *event, unsigned long offset, unsigned long head)
 {
-       if (event->header.misc & PERF_EVENT_MISC_OVERFLOW)
-               return process_overflow_event(event, offset, head);
-
        switch (event->header.type) {
+       case PERF_EVENT_SAMPLE:
+               return process_sample_event(event, offset, head);
+
        case PERF_EVENT_MMAP:
                return process_mmap_event(event, offset, head);
 
index d7ebbd7..d18546f 100644 (file)
@@ -14,6 +14,8 @@
 #include "util/parse-events.h"
 #include "util/string.h"
 
+#include "util/header.h"
+
 #include <unistd.h>
 #include <sched.h>
 
@@ -39,6 +41,8 @@ static int                    force                           = 0;
 static int                     append_file                     = 0;
 static int                     call_graph                      = 0;
 static int                     verbose                         = 0;
+static int                     inherit_stat                    = 0;
+static int                     no_samples                      = 0;
 
 static long                    samples;
 static struct timeval          last_read;
@@ -52,7 +56,8 @@ static int                    nr_poll;
 static int                     nr_cpu;
 
 static int                     file_new = 1;
-static struct perf_file_header file_header;
+
+struct perf_header             *header;
 
 struct mmap_event {
        struct perf_event_header        header;
@@ -306,12 +311,11 @@ static void pid_synthesize_mmap_samples(pid_t pid)
                        continue;
                pbf += n + 3;
                if (*pbf == 'x') { /* vm_exec */
-                       char *execname = strrchr(bf, ' ');
+                       char *execname = strchr(bf, '/');
 
-                       if (execname == NULL || execname[1] != '/')
+                       if (execname == NULL)
                                continue;
 
-                       execname += 1;
                        size = strlen(execname);
                        execname[size - 1] = '\0'; /* Remove \n */
                        memcpy(mmap_ev.filename, execname, size);
@@ -329,7 +333,7 @@ static void pid_synthesize_mmap_samples(pid_t pid)
        fclose(fp);
 }
 
-static void synthesize_samples(void)
+static void synthesize_all(void)
 {
        DIR *proc;
        struct dirent dirent, *next;
@@ -353,10 +357,35 @@ static void synthesize_samples(void)
 
 static int group_fd;
 
+static struct perf_header_attr *get_header_attr(struct perf_counter_attr *a, int nr)
+{
+       struct perf_header_attr *h_attr;
+
+       if (nr < header->attrs) {
+               h_attr = header->attr[nr];
+       } else {
+               h_attr = perf_header_attr__new(a);
+               perf_header__add_attr(header, h_attr);
+       }
+
+       return h_attr;
+}
+
 static void create_counter(int counter, int cpu, pid_t pid)
 {
        struct perf_counter_attr *attr = attrs + counter;
-       int track = 1;
+       struct perf_header_attr *h_attr;
+       int track = !counter; /* only the first counter needs these */
+       struct {
+               u64 count;
+               u64 time_enabled;
+               u64 time_running;
+               u64 id;
+       } read_data;
+
+       attr->read_format       = PERF_FORMAT_TOTAL_TIME_ENABLED |
+                                 PERF_FORMAT_TOTAL_TIME_RUNNING |
+                                 PERF_FORMAT_ID;
 
        attr->sample_type       = PERF_SAMPLE_IP | PERF_SAMPLE_TID;
 
@@ -366,25 +395,20 @@ static void create_counter(int counter, int cpu, pid_t pid)
                attr->sample_freq       = freq;
        }
 
+       if (no_samples)
+               attr->sample_freq = 0;
+
+       if (inherit_stat)
+               attr->inherit_stat = 1;
+
        if (call_graph)
                attr->sample_type       |= PERF_SAMPLE_CALLCHAIN;
 
-       if (file_new) {
-               file_header.sample_type = attr->sample_type;
-       } else {
-               if (file_header.sample_type != attr->sample_type) {
-                       fprintf(stderr, "incompatible append\n");
-                       exit(-1);
-               }
-       }
-
        attr->mmap              = track;
        attr->comm              = track;
        attr->inherit           = (cpu < 0) && inherit;
        attr->disabled          = 1;
 
-       track = 0; /* only the first counter needs these */
-
 try_again:
        fd[nr_cpu][counter] = sys_perf_counter_open(attr, pid, cpu, group_fd, 0);
 
@@ -415,6 +439,22 @@ try_again:
                exit(-1);
        }
 
+       h_attr = get_header_attr(attr, counter);
+
+       if (!file_new) {
+               if (memcmp(&h_attr->attr, attr, sizeof(*attr))) {
+                       fprintf(stderr, "incompatible append\n");
+                       exit(-1);
+               }
+       }
+
+       if (read(fd[nr_cpu][counter], &read_data, sizeof(read_data)) == -1) {
+               perror("Unable to read perf file descriptor\n");
+               exit(-1);
+       }
+
+       perf_header_attr__add_id(h_attr, read_data.id);
+
        assert(fd[nr_cpu][counter] >= 0);
        fcntl(fd[nr_cpu][counter], F_SETFL, O_NONBLOCK);
 
@@ -445,11 +485,6 @@ static void open_counters(int cpu, pid_t pid)
 {
        int counter;
 
-       if (pid > 0) {
-               pid_synthesize_comm_event(pid, 0);
-               pid_synthesize_mmap_samples(pid);
-       }
-
        group_fd = -1;
        for (counter = 0; counter < nr_counters; counter++)
                create_counter(counter, cpu, pid);
@@ -459,17 +494,16 @@ static void open_counters(int cpu, pid_t pid)
 
 static void atexit_header(void)
 {
-       file_header.data_size += bytes_written;
+       header->data_size += bytes_written;
 
-       if (pwrite(output, &file_header, sizeof(file_header), 0) == -1)
-               perror("failed to write on file headers");
+       perf_header__write(header, output);
 }
 
 static int __cmd_record(int argc, const char **argv)
 {
        int i, counter;
        struct stat st;
-       pid_t pid;
+       pid_t pid = 0;
        int flags;
        int ret;
 
@@ -500,22 +534,31 @@ static int __cmd_record(int argc, const char **argv)
                exit(-1);
        }
 
-       if (!file_new) {
-               if (read(output, &file_header, sizeof(file_header)) == -1) {
-                       perror("failed to read file headers");
-                       exit(-1);
-               }
-
-               lseek(output, file_header.data_size, SEEK_CUR);
-       }
+       if (!file_new)
+               header = perf_header__read(output);
+       else
+               header = perf_header__new();
 
        atexit(atexit_header);
 
        if (!system_wide) {
-               open_counters(-1, target_pid != -1 ? target_pid : getpid());
+               pid = target_pid;
+               if (pid == -1)
+                       pid = getpid();
+
+               open_counters(-1, pid);
        } else for (i = 0; i < nr_cpus; i++)
                open_counters(i, target_pid);
 
+       if (file_new)
+               perf_header__write(header, output);
+
+       if (!system_wide) {
+               pid_synthesize_comm_event(pid, 0);
+               pid_synthesize_mmap_samples(pid);
+       } else
+               synthesize_all();
+
        if (target_pid == -1 && argc) {
                pid = fork();
                if (pid < 0)
@@ -539,10 +582,7 @@ static int __cmd_record(int argc, const char **argv)
                }
        }
 
-       if (system_wide)
-               synthesize_samples();
-
-       while (!done) {
+       for (;;) {
                int hits = samples;
 
                for (i = 0; i < nr_cpu; i++) {
@@ -550,8 +590,11 @@ static int __cmd_record(int argc, const char **argv)
                                mmap_read(&mmap_array[i][counter]);
                }
 
-               if (hits == samples)
+               if (hits == samples) {
+                       if (done)
+                               break;
                        ret = poll(event_array, nr_poll, 100);
+               }
        }
 
        /*
@@ -600,6 +643,10 @@ static const struct option options[] = {
                    "do call-graph (stack chain/backtrace) recording"),
        OPT_BOOLEAN('v', "verbose", &verbose,
                    "be more verbose (show counter open errors, etc)"),
+       OPT_BOOLEAN('s', "stat", &inherit_stat,
+                   "per thread counts"),
+       OPT_BOOLEAN('n', "no-samples", &no_samples,
+                   "don't sample"),
        OPT_END()
 };
 
index 5eb5566..135b783 100644 (file)
 #include "util/rbtree.h"
 #include "util/symbol.h"
 #include "util/string.h"
+#include "util/callchain.h"
+#include "util/strlist.h"
 
 #include "perf.h"
+#include "util/header.h"
 
 #include "util/parse-options.h"
 #include "util/parse-events.h"
@@ -30,6 +33,8 @@ static char           *vmlinux = NULL;
 
 static char            default_sort_order[] = "comm,dso";
 static char            *sort_order = default_sort_order;
+static char            *dso_list_str, *comm_list_str, *sym_list_str;
+static struct strlist  *dso_list, *comm_list, *sym_list;
 
 static int             input;
 static int             show_mask = SHOW_KERNEL | SHOW_USER | SHOW_HV;
@@ -51,6 +56,9 @@ static char           *parent_pattern = default_parent_pattern;
 static regex_t         parent_regex;
 
 static int             exclude_other = 1;
+static int             callchain;
+
+static u64             sample_type;
 
 struct ip_event {
        struct perf_event_header header;
@@ -59,11 +67,6 @@ struct ip_event {
        unsigned char __more_data[];
 };
 
-struct ip_callchain {
-       u64 nr;
-       u64 ips[0];
-};
-
 struct mmap_event {
        struct perf_event_header header;
        u32 pid, tid;
@@ -97,6 +100,13 @@ struct lost_event {
        u64 lost;
 };
 
+struct read_event {
+       struct perf_event_header header;
+       u32 pid,tid;
+       u64 value;
+       u64 format[3];
+};
+
 typedef union event_union {
        struct perf_event_header        header;
        struct ip_event                 ip;
@@ -105,6 +115,7 @@ typedef union event_union {
        struct fork_event               fork;
        struct period_event             period;
        struct lost_event               lost;
+       struct read_event               read;
 } event_t;
 
 static LIST_HEAD(dsos);
@@ -229,7 +240,7 @@ static u64 vdso__map_ip(struct map *map, u64 ip)
 
 static inline int is_anon_memory(const char *filename)
 {
-     return strcmp(filename, "//anon") == 0;
+       return strcmp(filename, "//anon") == 0;
 }
 
 static struct map *map__new(struct mmap_event *event)
@@ -400,9 +411,27 @@ static void thread__insert_map(struct thread *self, struct map *map)
 
        list_for_each_entry_safe(pos, tmp, &self->maps, node) {
                if (map__overlap(pos, map)) {
-                       list_del_init(&pos->node);
-                       /* XXX leaks dsos */
-                       free(pos);
+                       if (verbose >= 2) {
+                               printf("overlapping maps:\n");
+                               map__fprintf(map, stdout);
+                               map__fprintf(pos, stdout);
+                       }
+
+                       if (map->start <= pos->start && map->end > pos->start)
+                               pos->start = map->end;
+
+                       if (map->end >= pos->end && map->start < pos->end)
+                               pos->end = map->start;
+
+                       if (verbose >= 2) {
+                               printf("after collision:\n");
+                               map__fprintf(pos, stdout);
+                       }
+
+                       if (pos->start >= pos->end) {
+                               list_del_init(&pos->node);
+                               free(pos);
+                       }
                }
        }
 
@@ -464,17 +493,19 @@ static size_t threads__fprintf(FILE *fp)
 static struct rb_root hist;
 
 struct hist_entry {
-       struct rb_node   rb_node;
-
-       struct thread    *thread;
-       struct map       *map;
-       struct dso       *dso;
-       struct symbol    *sym;
-       struct symbol    *parent;
-       u64              ip;
-       char             level;
-
-       u64              count;
+       struct rb_node          rb_node;
+
+       struct thread           *thread;
+       struct map              *map;
+       struct dso              *dso;
+       struct symbol           *sym;
+       struct symbol           *parent;
+       u64                     ip;
+       char                    level;
+       struct callchain_node   callchain;
+       struct rb_root          sorted_chain;
+
+       u64                     count;
 };
 
 /*
@@ -745,6 +776,48 @@ hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
 }
 
 static size_t
+callchain__fprintf(FILE *fp, struct callchain_node *self, u64 total_samples)
+{
+       struct callchain_list *chain;
+       size_t ret = 0;
+
+       if (!self)
+               return 0;
+
+       ret += callchain__fprintf(fp, self->parent, total_samples);
+
+
+       list_for_each_entry(chain, &self->val, list)
+               ret += fprintf(fp, "                %p\n", (void *)chain->ip);
+
+       return ret;
+}
+
+static size_t
+hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self,
+                             u64 total_samples)
+{
+       struct rb_node *rb_node;
+       struct callchain_node *chain;
+       size_t ret = 0;
+
+       rb_node = rb_first(&self->sorted_chain);
+       while (rb_node) {
+               double percent;
+
+               chain = rb_entry(rb_node, struct callchain_node, rb_node);
+               percent = chain->hit * 100.0 / total_samples;
+               ret += fprintf(fp, "           %6.2f%%\n", percent);
+               ret += callchain__fprintf(fp, chain, total_samples);
+               ret += fprintf(fp, "\n");
+               rb_node = rb_next(rb_node);
+       }
+
+       return ret;
+}
+
+
+static size_t
 hist_entry__fprintf(FILE *fp, struct hist_entry *self, u64 total_samples)
 {
        struct sort_entry *se;
@@ -784,6 +857,9 @@ hist_entry__fprintf(FILE *fp, struct hist_entry *self, u64 total_samples)
 
        ret += fprintf(fp, "\n");
 
+       if (callchain)
+               hist_entry_callchain__fprintf(fp, self, total_samples);
+
        return ret;
 }
 
@@ -797,7 +873,7 @@ resolve_symbol(struct thread *thread, struct map **mapp,
 {
        struct dso *dso = dsop ? *dsop : NULL;
        struct map *map = mapp ? *mapp : NULL;
-       uint64_t ip = *ipp;
+       u64 ip = *ipp;
 
        if (!thread)
                return NULL;
@@ -814,7 +890,6 @@ resolve_symbol(struct thread *thread, struct map **mapp,
                        *mapp = map;
 got_map:
                ip = map->map_ip(map, ip);
-               *ipp  = ip;
 
                dso = map->dso;
        } else {
@@ -828,6 +903,8 @@ got_map:
                dso = kernel_dso;
        }
        dprintf(" ...... dso: %s\n", dso ? dso->name : "<not found>");
+       dprintf(" ...... map: %Lx -> %Lx\n", *ipp, ip);
+       *ipp  = ip;
 
        if (dsop)
                *dsop = dso;
@@ -867,6 +944,7 @@ hist_entry__add(struct thread *thread, struct map *map, struct dso *dso,
                .level  = level,
                .count  = count,
                .parent = NULL,
+               .sorted_chain = RB_ROOT
        };
        int cmp;
 
@@ -909,6 +987,8 @@ hist_entry__add(struct thread *thread, struct map *map, struct dso *dso,
 
                if (!cmp) {
                        he->count += count;
+                       if (callchain)
+                               append_chain(&he->callchain, chain);
                        return 0;
                }
 
@@ -922,6 +1002,10 @@ hist_entry__add(struct thread *thread, struct map *map, struct dso *dso,
        if (!he)
                return -ENOMEM;
        *he = entry;
+       if (callchain) {
+               callchain_init(&he->callchain);
+               append_chain(&he->callchain, chain);
+       }
        rb_link_node(&he->rb_node, parent, p);
        rb_insert_color(&he->rb_node, &hist);
 
@@ -998,6 +1082,9 @@ static void output__insert_entry(struct hist_entry *he)
        struct rb_node *parent = NULL;
        struct hist_entry *iter;
 
+       if (callchain)
+               sort_chain_to_rbtree(&he->sorted_chain, &he->callchain);
+
        while (*p != NULL) {
                parent = *p;
                iter = rb_entry(parent, struct hist_entry, rb_node);
@@ -1115,7 +1202,7 @@ static int validate_chain(struct ip_callchain *chain, event_t *event)
 }
 
 static int
-process_overflow_event(event_t *event, unsigned long offset, unsigned long head)
+process_sample_event(event_t *event, unsigned long offset, unsigned long head)
 {
        char level;
        int show = 0;
@@ -1127,12 +1214,12 @@ process_overflow_event(event_t *event, unsigned long offset, unsigned long head)
        void *more_data = event->ip.__more_data;
        struct ip_callchain *chain = NULL;
 
-       if (event->header.type & PERF_SAMPLE_PERIOD) {
+       if (sample_type & PERF_SAMPLE_PERIOD) {
                period = *(u64 *)more_data;
                more_data += sizeof(u64);
        }
 
-       dprintf("%p [%p]: PERF_EVENT (IP, %d): %d: %p period: %Ld\n",
+       dprintf("%p [%p]: PERF_EVENT_SAMPLE (IP, %d): %d: %p period: %Ld\n",
                (void *)(offset + head),
                (void *)(long)(event->header.size),
                event->header.misc,
@@ -1140,7 +1227,7 @@ process_overflow_event(event_t *event, unsigned long offset, unsigned long head)
                (void *)(long)ip,
                (long long)period);
 
-       if (event->header.type & PERF_SAMPLE_CALLCHAIN) {
+       if (sample_type & PERF_SAMPLE_CALLCHAIN) {
                int i;
 
                chain = (void *)more_data;
@@ -1166,6 +1253,9 @@ process_overflow_event(event_t *event, unsigned long offset, unsigned long head)
                return -1;
        }
 
+       if (comm_list && !strlist__has_entry(comm_list, thread->comm))
+               return 0;
+
        if (event->header.misc & PERF_EVENT_MISC_KERNEL) {
                show = SHOW_KERNEL;
                level = 'k';
@@ -1188,6 +1278,12 @@ process_overflow_event(event_t *event, unsigned long offset, unsigned long head)
        if (show & show_mask) {
                struct symbol *sym = resolve_symbol(thread, &map, &dso, &ip);
 
+               if (dso_list && dso && dso->name && !strlist__has_entry(dso_list, dso->name))
+                       return 0;
+
+               if (sym_list && sym && !strlist__has_entry(sym_list, sym->name))
+                       return 0;
+
                if (hist_entry__add(thread, map, dso, sym, ip, chain, level, period)) {
                        eprintf("problem incrementing symbol count, skipping event\n");
                        return -1;
@@ -1328,14 +1424,27 @@ static void trace_event(event_t *event)
 }
 
 static int
+process_read_event(event_t *event, unsigned long offset, unsigned long head)
+{
+       dprintf("%p [%p]: PERF_EVENT_READ: %d %d %Lu\n",
+                       (void *)(offset + head),
+                       (void *)(long)(event->header.size),
+                       event->read.pid,
+                       event->read.tid,
+                       event->read.value);
+
+       return 0;
+}
+
+static int
 process_event(event_t *event, unsigned long offset, unsigned long head)
 {
        trace_event(event);
 
-       if (event->header.misc & PERF_EVENT_MISC_OVERFLOW)
-               return process_overflow_event(event, offset, head);
-
        switch (event->header.type) {
+       case PERF_EVENT_SAMPLE:
+               return process_sample_event(event, offset, head);
+
        case PERF_EVENT_MMAP:
                return process_mmap_event(event, offset, head);
 
@@ -1351,6 +1460,9 @@ process_event(event_t *event, unsigned long offset, unsigned long head)
        case PERF_EVENT_LOST:
                return process_lost_event(event, offset, head);
 
+       case PERF_EVENT_READ:
+               return process_read_event(event, offset, head);
+
        /*
         * We dont process them right now but they are fine:
         */
@@ -1366,13 +1478,30 @@ process_event(event_t *event, unsigned long offset, unsigned long head)
        return 0;
 }
 
-static struct perf_file_header         file_header;
+static struct perf_header      *header;
+
+static u64 perf_header__sample_type(void)
+{
+       u64 sample_type = 0;
+       int i;
+
+       for (i = 0; i < header->attrs; i++) {
+               struct perf_header_attr *attr = header->attr[i];
+
+               if (!sample_type)
+                       sample_type = attr->attr.sample_type;
+               else if (sample_type != attr->attr.sample_type)
+                       die("non matching sample_type");
+       }
+
+       return sample_type;
+}
 
 static int __cmd_report(void)
 {
        int ret, rc = EXIT_FAILURE;
        unsigned long offset = 0;
-       unsigned long head = sizeof(file_header);
+       unsigned long head, shift;
        struct stat stat;
        event_t *event;
        uint32_t size;
@@ -1400,13 +1529,12 @@ static int __cmd_report(void)
                exit(0);
        }
 
-       if (read(input, &file_header, sizeof(file_header)) == -1) {
-               perror("failed to read file headers");
-               exit(-1);
-       }
+       header = perf_header__read(input);
+       head = header->data_offset;
 
-       if (sort__has_parent &&
-           !(file_header.sample_type & PERF_SAMPLE_CALLCHAIN)) {
+       sample_type = perf_header__sample_type();
+
+       if (sort__has_parent && !(sample_type & PERF_SAMPLE_CALLCHAIN)) {
                fprintf(stderr, "selected --sort parent, but no callchain data\n");
                exit(-1);
        }
@@ -1426,6 +1554,11 @@ static int __cmd_report(void)
                cwd = NULL;
                cwdlen = 0;
        }
+
+       shift = page_size * (head / page_size);
+       offset += shift;
+       head -= shift;
+
 remap:
        buf = (char *)mmap(NULL, page_size * mmap_window, PROT_READ,
                           MAP_SHARED, input, offset);
@@ -1442,9 +1575,10 @@ more:
                size = 8;
 
        if (head + event->header.size >= page_size * mmap_window) {
-               unsigned long shift = page_size * (head / page_size);
                int ret;
 
+               shift = page_size * (head / page_size);
+
                ret = munmap(buf, page_size * mmap_window);
                assert(ret == 0);
 
@@ -1482,7 +1616,7 @@ more:
 
        head += size;
 
-       if (offset + head >= sizeof(file_header) + file_header.data_size)
+       if (offset + head >= header->data_offset + header->data_size)
                goto done;
 
        if (offset + head < stat.st_size)
@@ -1536,6 +1670,13 @@ static const struct option options[] = {
                   "regex filter to identify parent, see: '--sort parent'"),
        OPT_BOOLEAN('x', "exclude-other", &exclude_other,
                    "Only display entries with parent-match"),
+       OPT_BOOLEAN('c', "callchain", &callchain, "Display callchains"),
+       OPT_STRING('d', "dsos", &dso_list_str, "dso[,dso...]",
+                  "only consider symbols in these dsos"),
+       OPT_STRING('C', "comms", &comm_list_str, "comm[,comm...]",
+                  "only consider symbols in these comms"),
+       OPT_STRING('S', "symbols", &sym_list_str, "symbol[,symbol...]",
+                  "only consider these symbols"),
        OPT_END()
 };
 
@@ -1554,6 +1695,19 @@ static void setup_sorting(void)
        free(str);
 }
 
+static void setup_list(struct strlist **list, const char *list_str,
+                      const char *list_name)
+{
+       if (list_str) {
+               *list = strlist__new(true, list_str);
+               if (!*list) {
+                       fprintf(stderr, "problems parsing %s list\n",
+                               list_name);
+                       exit(129);
+               }
+       }
+}
+
 int cmd_report(int argc, const char **argv, const char *prefix)
 {
        symbol__init();
@@ -1575,6 +1729,10 @@ int cmd_report(int argc, const char **argv, const char *prefix)
        if (argc)
                usage_with_options(report_usage, options);
 
+       setup_list(&dso_list, dso_list_str, "dso");
+       setup_list(&comm_list, comm_list_str, "comm");
+       setup_list(&sym_list, sym_list_str, "symbol");
+
        setup_pager();
 
        return __cmd_report();
index 6d3eeac..2e03524 100644 (file)
@@ -32,6 +32,7 @@
  *   Wu Fengguang <fengguang.wu@intel.com>
  *   Mike Galbraith <efault@gmx.de>
  *   Paul Mackerras <paulus@samba.org>
+ *   Jaswinder Singh Rajput <jaswinder@kernel.org>
  *
  * Released under the GPL v2. (and only v2, not any later version)
  */
@@ -45,7 +46,7 @@
 #include <sys/prctl.h>
 #include <math.h>
 
-static struct perf_counter_attr default_attrs[MAX_COUNTERS] = {
+static struct perf_counter_attr default_attrs[] = {
 
   { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_TASK_CLOCK     },
   { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_CONTEXT_SWITCHES},
@@ -59,42 +60,28 @@ static struct perf_counter_attr default_attrs[MAX_COUNTERS] = {
 
 };
 
+#define MAX_RUN                        100
+
 static int                     system_wide                     =  0;
-static int                     inherit                         =  1;
 static int                     verbose                         =  0;
-
-static int                     fd[MAX_NR_CPUS][MAX_COUNTERS];
-
-static int                     target_pid                      = -1;
 static int                     nr_cpus                         =  0;
-static unsigned int            page_size;
+static int                     run_idx                         =  0;
 
+static int                     run_count                       =  1;
+static int                     inherit                         =  1;
 static int                     scale                           =  1;
+static int                     target_pid                      = -1;
+static int                     null_run                        =  0;
 
-static const unsigned int default_count[] = {
-       1000000,
-       1000000,
-         10000,
-         10000,
-       1000000,
-         10000,
-};
-
-#define MAX_RUN 100
-
-static int                     run_count               =  1;
-static int                     run_idx                 =  0;
-
-static u64                     event_res[MAX_RUN][MAX_COUNTERS][3];
-static u64                     event_scaled[MAX_RUN][MAX_COUNTERS];
-
-//static u64                   event_hist[MAX_RUN][MAX_COUNTERS][3];
-
+static int                     fd[MAX_NR_CPUS][MAX_COUNTERS];
 
 static u64                     runtime_nsecs[MAX_RUN];
 static u64                     walltime_nsecs[MAX_RUN];
 static u64                     runtime_cycles[MAX_RUN];
 
+static u64                     event_res[MAX_RUN][MAX_COUNTERS][3];
+static u64                     event_scaled[MAX_RUN][MAX_COUNTERS];
+
 static u64                     event_res_avg[MAX_COUNTERS][3];
 static u64                     event_res_noise[MAX_COUNTERS][3];
 
@@ -109,7 +96,10 @@ static u64                  walltime_nsecs_noise;
 static u64                     runtime_cycles_avg;
 static u64                     runtime_cycles_noise;
 
-static void create_perf_stat_counter(int counter)
+#define ERR_PERF_OPEN \
+"Error: counter %d, sys_perf_counter_open() syscall returned with %d (%s)\n"
+
+static void create_perf_stat_counter(int counter, int pid)
 {
        struct perf_counter_attr *attr = attrs + counter;
 
@@ -119,20 +109,21 @@ static void create_perf_stat_counter(int counter)
 
        if (system_wide) {
                int cpu;
-               for (cpu = 0; cpu < nr_cpus; cpu ++) {
+               for (cpu = 0; cpu < nr_cpus; cpu++) {
                        fd[cpu][counter] = sys_perf_counter_open(attr, -1, cpu, -1, 0);
-                       if (fd[cpu][counter] < 0 && verbose) {
-                               printf("Error: counter %d, sys_perf_counter_open() syscall returned with %d (%s)\n", counter, fd[cpu][counter], strerror(errno));
-                       }
+                       if (fd[cpu][counter] < 0 && verbose)
+                               fprintf(stderr, ERR_PERF_OPEN, counter,
+                                       fd[cpu][counter], strerror(errno));
                }
        } else {
-               attr->inherit   = inherit;
-               attr->disabled  = 1;
-
-               fd[0][counter] = sys_perf_counter_open(attr, 0, -1, -1, 0);
-               if (fd[0][counter] < 0 && verbose) {
-                       printf("Error: counter %d, sys_perf_counter_open() syscall returned with %d (%s)\n", counter, fd[0][counter], strerror(errno));
-               }
+               attr->inherit        = inherit;
+               attr->disabled       = 1;
+               attr->enable_on_exec = 1;
+
+               fd[0][counter] = sys_perf_counter_open(attr, pid, -1, -1, 0);
+               if (fd[0][counter] < 0 && verbose)
+                       fprintf(stderr, ERR_PERF_OPEN, counter,
+                               fd[0][counter], strerror(errno));
        }
 }
 
@@ -168,7 +159,7 @@ static void read_counter(int counter)
        count[0] = count[1] = count[2] = 0;
 
        nv = scale ? 3 : 1;
-       for (cpu = 0; cpu < nr_cpus; cpu ++) {
+       for (cpu = 0; cpu < nr_cpus; cpu++) {
                if (fd[cpu][counter] < 0)
                        continue;
 
@@ -215,32 +206,67 @@ static int run_perf_stat(int argc, const char **argv)
        int status = 0;
        int counter;
        int pid;
+       int child_ready_pipe[2], go_pipe[2];
+       char buf;
 
        if (!system_wide)
                nr_cpus = 1;
 
-       for (counter = 0; counter < nr_counters; counter++)
-               create_perf_stat_counter(counter);
-
-       /*
-        * Enable counters and exec the command:
-        */
-       t0 = rdclock();
-       prctl(PR_TASK_PERF_COUNTERS_ENABLE);
+       if (pipe(child_ready_pipe) < 0 || pipe(go_pipe) < 0) {
+               perror("failed to create pipes");
+               exit(1);
+       }
 
        if ((pid = fork()) < 0)
                perror("failed to fork");
 
        if (!pid) {
-               if (execvp(argv[0], (char **)argv)) {
-                       perror(argv[0]);
-                       exit(-1);
-               }
+               close(child_ready_pipe[0]);
+               close(go_pipe[1]);
+               fcntl(go_pipe[0], F_SETFD, FD_CLOEXEC);
+
+               /*
+                * Do a dummy execvp to get the PLT entry resolved,
+                * so we avoid the resolver overhead on the real
+                * execvp call.
+                */
+               execvp("", (char **)argv);
+
+               /*
+                * Tell the parent we're ready to go
+                */
+               close(child_ready_pipe[1]);
+
+               /*
+                * Wait until the parent tells us to go.
+                */
+               read(go_pipe[0], &buf, 1);
+
+               execvp(argv[0], (char **)argv);
+
+               perror(argv[0]);
+               exit(-1);
        }
 
+       /*
+        * Wait for the child to be ready to exec.
+        */
+       close(child_ready_pipe[1]);
+       close(go_pipe[0]);
+       read(child_ready_pipe[0], &buf, 1);
+       close(child_ready_pipe[0]);
+
+       for (counter = 0; counter < nr_counters; counter++)
+               create_perf_stat_counter(counter, pid);
+
+       /*
+        * Enable counters and exec the command:
+        */
+       t0 = rdclock();
+
+       close(go_pipe[1]);
        wait(&status);
 
-       prctl(PR_TASK_PERF_COUNTERS_DISABLE);
        t1 = rdclock();
 
        walltime_nsecs[run_idx] = t1 - t0;
@@ -262,7 +288,7 @@ static void nsec_printout(int counter, u64 *count, u64 *noise)
 {
        double msecs = (double)count[0] / 1000000;
 
-       fprintf(stderr, " %14.6f  %-20s", msecs, event_name(counter));
+       fprintf(stderr, " %14.6f  %-24s", msecs, event_name(counter));
 
        if (attrs[counter].type == PERF_TYPE_SOFTWARE &&
                attrs[counter].config == PERF_COUNT_SW_TASK_CLOCK) {
@@ -276,7 +302,7 @@ static void nsec_printout(int counter, u64 *count, u64 *noise)
 
 static void abs_printout(int counter, u64 *count, u64 *noise)
 {
-       fprintf(stderr, " %14Ld  %-20s", count[0], event_name(counter));
+       fprintf(stderr, " %14Ld  %-24s", count[0], event_name(counter));
 
        if (runtime_cycles_avg &&
                attrs[counter].type == PERF_TYPE_HARDWARE &&
@@ -306,7 +332,7 @@ static void print_counter(int counter)
        scaled = event_scaled_avg[counter];
 
        if (scaled == -1) {
-               fprintf(stderr, " %14s  %-20s\n",
+               fprintf(stderr, " %14s  %-24s\n",
                        "<not counted>", event_name(counter));
                return;
        }
@@ -364,8 +390,11 @@ static void calc_avg(void)
                                event_res_avg[j]+1, event_res[i][j]+1);
                        update_avg("counter/2", j,
                                event_res_avg[j]+2, event_res[i][j]+2);
-                       update_avg("scaled", j,
-                               event_scaled_avg + j, event_scaled[i]+j);
+                       if (event_scaled[i][j] != -1)
+                               update_avg("scaled", j,
+                                       event_scaled_avg + j, event_scaled[i]+j);
+                       else
+                               event_scaled_avg[j] = -1;
                }
        }
        runtime_nsecs_avg /= run_count;
@@ -429,11 +458,14 @@ static void print_stat(int argc, const char **argv)
        for (counter = 0; counter < nr_counters; counter++)
                print_counter(counter);
 
-
        fprintf(stderr, "\n");
-       fprintf(stderr, " %14.9f  seconds time elapsed.\n",
+       fprintf(stderr, " %14.9f  seconds time elapsed",
                        (double)walltime_nsecs_avg/1e9);
-       fprintf(stderr, "\n");
+       if (run_count > 1) {
+               fprintf(stderr, "   ( +- %7.3f%% )",
+                       100.0*(double)walltime_nsecs_noise/(double)walltime_nsecs_avg);
+       }
+       fprintf(stderr, "\n\n");
 }
 
 static volatile int signr = -1;
@@ -466,13 +498,15 @@ static const struct option options[] = {
        OPT_INTEGER('p', "pid", &target_pid,
                    "stat events on existing pid"),
        OPT_BOOLEAN('a', "all-cpus", &system_wide,
-                           "system-wide collection from all CPUs"),
+                   "system-wide collection from all CPUs"),
        OPT_BOOLEAN('S', "scale", &scale,
-                           "scale/normalize counters"),
+                   "scale/normalize counters"),
        OPT_BOOLEAN('v', "verbose", &verbose,
                    "be more verbose (show counter open errors, etc)"),
        OPT_INTEGER('r', "repeat", &run_count,
                    "repeat command and print average + stddev (max: 100)"),
+       OPT_BOOLEAN('n', "null", &null_run,
+                   "null run - dont start any counters"),
        OPT_END()
 };
 
@@ -480,18 +514,17 @@ int cmd_stat(int argc, const char **argv, const char *prefix)
 {
        int status;
 
-       page_size = sysconf(_SC_PAGE_SIZE);
-
-       memcpy(attrs, default_attrs, sizeof(attrs));
-
        argc = parse_options(argc, argv, options, stat_usage, 0);
        if (!argc)
                usage_with_options(stat_usage, options);
        if (run_count <= 0 || run_count > MAX_RUN)
                usage_with_options(stat_usage, options);
 
-       if (!nr_counters)
-               nr_counters = 8;
+       /* Set attrs and nr_counters if no event is selected and !null_run */
+       if (!null_run && !nr_counters) {
+               memcpy(attrs, default_attrs, sizeof(default_attrs));
+               nr_counters = ARRAY_SIZE(default_attrs);
+       }
 
        nr_cpus = sysconf(_SC_NPROCESSORS_ONLN);
        assert(nr_cpus <= MAX_NR_CPUS);
@@ -511,7 +544,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix)
        status = 0;
        for (run_idx = 0; run_idx < run_count; run_idx++) {
                if (run_count != 1 && verbose)
-                       fprintf(stderr, "[ perf stat: executing run #%d ... ]\n", run_idx+1);
+                       fprintf(stderr, "[ perf stat: executing run #%d ... ]\n", run_idx + 1);
                status = run_perf_stat(argc, argv);
        }
 
index 5352b5e..cf0d21f 100644 (file)
@@ -392,11 +392,11 @@ static void record_ip(u64 ip, int counter)
        samples--;
 }
 
-static void process_event(u64 ip, int counter)
+static void process_event(u64 ip, int counter, int user)
 {
        samples++;
 
-       if (ip < min_ip || ip > max_ip) {
+       if (user) {
                userspace_samples++;
                return;
        }
@@ -509,9 +509,10 @@ static void mmap_read_counter(struct mmap_data *md)
 
                old += size;
 
-               if (event->header.misc & PERF_EVENT_MISC_OVERFLOW) {
-                       if (event->header.type & PERF_SAMPLE_IP)
-                               process_event(event->ip.ip, md->counter);
+               if (event->header.type == PERF_EVENT_SAMPLE) {
+                       int user =
+       (event->header.misc & PERF_EVENT_MISC_CPUMODE_MASK) == PERF_EVENT_MISC_USER;
+                       process_event(event->ip.ip, md->counter, user);
                }
        }
 
index ceb68aa..d3042a6 100644 (file)
 #define cpu_relax()    asm volatile("" ::: "memory");
 #endif
 
+#ifdef __sh__
+#include "../../arch/sh/include/asm/unistd.h"
+#if defined(__SH4A__) || defined(__SH5__)
+# define rmb()         asm volatile("synco" ::: "memory")
+#else
+# define rmb()         asm volatile("" ::: "memory")
+#endif
+#define cpu_relax()    asm volatile("" ::: "memory")
+#endif
+
+#ifdef __hppa__
+#include "../../arch/parisc/include/asm/unistd.h"
+#define rmb()          asm volatile("" ::: "memory")
+#define cpu_relax()    asm volatile("" ::: "memory");
+#endif
+
 #include <time.h>
 #include <unistd.h>
 #include <sys/types.h>
 #include <sys/syscall.h>
 
 #include "../../include/linux/perf_counter.h"
-#include "types.h"
+#include "util/types.h"
 
 /*
  * prctl(PR_TASK_PERF_COUNTERS_DISABLE) will (cheaply) disable all
@@ -72,10 +88,9 @@ sys_perf_counter_open(struct perf_counter_attr *attr,
 #define MAX_COUNTERS                   256
 #define MAX_NR_CPUS                    256
 
-struct perf_file_header {
-       u64     version;
-       u64     sample_type;
-       u64     data_size;
+struct ip_callchain {
+       u64 nr;
+       u64 ips[0];
 };
 
 #endif
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c
new file mode 100644 (file)
index 0000000..ad3c285
--- /dev/null
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2009, Frederic Weisbecker <fweisbec@gmail.com>
+ *
+ * Handle the callchains from the stream in an ad-hoc radix tree and then
+ * sort them in an rbtree.
+ *
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <errno.h>
+
+#include "callchain.h"
+
+
+static void rb_insert_callchain(struct rb_root *root, struct callchain_node *chain)
+{
+       struct rb_node **p = &root->rb_node;
+       struct rb_node *parent = NULL;
+       struct callchain_node *rnode;
+
+       while (*p) {
+               parent = *p;
+               rnode = rb_entry(parent, struct callchain_node, rb_node);
+
+               if (rnode->hit < chain->hit)
+                       p = &(*p)->rb_left;
+               else
+                       p = &(*p)->rb_right;
+       }
+
+       rb_link_node(&chain->rb_node, parent, p);
+       rb_insert_color(&chain->rb_node, root);
+}
+
+/*
+ * Once we get every callchains from the stream, we can now
+ * sort them by hit
+ */
+void sort_chain_to_rbtree(struct rb_root *rb_root, struct callchain_node *node)
+{
+       struct callchain_node *child;
+
+       list_for_each_entry(child, &node->children, brothers)
+               sort_chain_to_rbtree(rb_root, child);
+
+       if (node->hit)
+               rb_insert_callchain(rb_root, node);
+}
+
+static struct callchain_node *create_child(struct callchain_node *parent)
+{
+       struct callchain_node *new;
+
+       new = malloc(sizeof(*new));
+       if (!new) {
+               perror("not enough memory to create child for code path tree");
+               return NULL;
+       }
+       new->parent = parent;
+       INIT_LIST_HEAD(&new->children);
+       INIT_LIST_HEAD(&new->val);
+       list_add_tail(&new->brothers, &parent->children);
+
+       return new;
+}
+
+static void
+fill_node(struct callchain_node *node, struct ip_callchain *chain, int start)
+{
+       int i;
+
+       for (i = start; i < chain->nr; i++) {
+               struct callchain_list *call;
+
+               call = malloc(sizeof(*chain));
+               if (!call) {
+                       perror("not enough memory for the code path tree");
+                       return;
+               }
+               call->ip = chain->ips[i];
+               list_add_tail(&call->list, &node->val);
+       }
+       node->val_nr = i - start;
+}
+
+static void add_child(struct callchain_node *parent, struct ip_callchain *chain)
+{
+       struct callchain_node *new;
+
+       new = create_child(parent);
+       fill_node(new, chain, parent->val_nr);
+
+       new->hit = 1;
+}
+
+static void
+split_add_child(struct callchain_node *parent, struct ip_callchain *chain,
+               struct callchain_list *to_split, int idx)
+{
+       struct callchain_node *new;
+
+       /* split */
+       new = create_child(parent);
+       list_move_tail(&to_split->list, &new->val);
+       new->hit = parent->hit;
+       parent->hit = 0;
+       parent->val_nr = idx;
+
+       /* create the new one */
+       add_child(parent, chain);
+}
+
+static int
+__append_chain(struct callchain_node *root, struct ip_callchain *chain,
+               int start);
+
+static int
+__append_chain_children(struct callchain_node *root, struct ip_callchain *chain)
+{
+       struct callchain_node *rnode;
+
+       /* lookup in childrens */
+       list_for_each_entry(rnode, &root->children, brothers) {
+               int ret = __append_chain(rnode, chain, root->val_nr);
+               if (!ret)
+                       return 0;
+       }
+       return -1;
+}
+
+static int
+__append_chain(struct callchain_node *root, struct ip_callchain *chain,
+               int start)
+{
+       struct callchain_list *cnode;
+       int i = start;
+       bool found = false;
+
+       /* lookup in the current node */
+       list_for_each_entry(cnode, &root->val, list) {
+               if (cnode->ip != chain->ips[i++])
+                       break;
+               if (!found)
+                       found = true;
+               if (i == chain->nr)
+                       break;
+       }
+
+       /* matches not, relay on the parent */
+       if (!found)
+               return -1;
+
+       /* we match only a part of the node. Split it and add the new chain */
+       if (i < root->val_nr) {
+               split_add_child(root, chain, cnode, i);
+               return 0;
+       }
+
+       /* we match 100% of the path, increment the hit */
+       if (i == root->val_nr) {
+               root->hit++;
+               return 0;
+       }
+
+       return __append_chain_children(root, chain);
+}
+
+void append_chain(struct callchain_node *root, struct ip_callchain *chain)
+{
+       if (__append_chain_children(root, chain) == -1)
+               add_child(root, chain);
+}
diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h
new file mode 100644 (file)
index 0000000..fa1cd2f
--- /dev/null
@@ -0,0 +1,33 @@
+#ifndef __PERF_CALLCHAIN_H
+#define __PERF_CALLCHAIN_H
+
+#include "../perf.h"
+#include "list.h"
+#include "rbtree.h"
+
+
+struct callchain_node {
+       struct callchain_node   *parent;
+       struct list_head        brothers;
+       struct list_head        children;
+       struct list_head        val;
+       struct rb_node          rb_node;
+       int                     val_nr;
+       int                     hit;
+};
+
+struct callchain_list {
+       unsigned long           ip;
+       struct list_head        list;
+};
+
+static inline void callchain_init(struct callchain_node *node)
+{
+       INIT_LIST_HEAD(&node->brothers);
+       INIT_LIST_HEAD(&node->children);
+       INIT_LIST_HEAD(&node->val);
+}
+
+void append_chain(struct callchain_node *root, struct ip_callchain *chain);
+void sort_chain_to_rbtree(struct rb_root *rb_root, struct callchain_node *node);
+#endif
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
new file mode 100644 (file)
index 0000000..450384b
--- /dev/null
@@ -0,0 +1,242 @@
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "util.h"
+#include "header.h"
+
+/*
+ *
+ */
+
+struct perf_header_attr *perf_header_attr__new(struct perf_counter_attr *attr)
+{
+       struct perf_header_attr *self = malloc(sizeof(*self));
+
+       if (!self)
+               die("nomem");
+
+       self->attr = *attr;
+       self->ids = 0;
+       self->size = 1;
+       self->id = malloc(sizeof(u64));
+
+       if (!self->id)
+               die("nomem");
+
+       return self;
+}
+
+void perf_header_attr__add_id(struct perf_header_attr *self, u64 id)
+{
+       int pos = self->ids;
+
+       self->ids++;
+       if (self->ids > self->size) {
+               self->size *= 2;
+               self->id = realloc(self->id, self->size * sizeof(u64));
+               if (!self->id)
+                       die("nomem");
+       }
+       self->id[pos] = id;
+}
+
+/*
+ *
+ */
+
+struct perf_header *perf_header__new(void)
+{
+       struct perf_header *self = malloc(sizeof(*self));
+
+       if (!self)
+               die("nomem");
+
+       self->frozen = 0;
+
+       self->attrs = 0;
+       self->size = 1;
+       self->attr = malloc(sizeof(void *));
+
+       if (!self->attr)
+               die("nomem");
+
+       self->data_offset = 0;
+       self->data_size = 0;
+
+       return self;
+}
+
+void perf_header__add_attr(struct perf_header *self,
+                          struct perf_header_attr *attr)
+{
+       int pos = self->attrs;
+
+       if (self->frozen)
+               die("frozen");
+
+       self->attrs++;
+       if (self->attrs > self->size) {
+               self->size *= 2;
+               self->attr = realloc(self->attr, self->size * sizeof(void *));
+               if (!self->attr)
+                       die("nomem");
+       }
+       self->attr[pos] = attr;
+}
+
+static const char *__perf_magic = "PERFFILE";
+
+#define PERF_MAGIC     (*(u64 *)__perf_magic)
+
+struct perf_file_section {
+       u64 offset;
+       u64 size;
+};
+
+struct perf_file_attr {
+       struct perf_counter_attr        attr;
+       struct perf_file_section        ids;
+};
+
+struct perf_file_header {
+       u64                             magic;
+       u64                             size;
+       u64                             attr_size;
+       struct perf_file_section        attrs;
+       struct perf_file_section        data;
+};
+
+static void do_write(int fd, void *buf, size_t size)
+{
+       while (size) {
+               int ret = write(fd, buf, size);
+
+               if (ret < 0)
+                       die("failed to write");
+
+               size -= ret;
+               buf += ret;
+       }
+}
+
+void perf_header__write(struct perf_header *self, int fd)
+{
+       struct perf_file_header f_header;
+       struct perf_file_attr   f_attr;
+       struct perf_header_attr *attr;
+       int i;
+
+       lseek(fd, sizeof(f_header), SEEK_SET);
+
+
+       for (i = 0; i < self->attrs; i++) {
+               attr = self->attr[i];
+
+               attr->id_offset = lseek(fd, 0, SEEK_CUR);
+               do_write(fd, attr->id, attr->ids * sizeof(u64));
+       }
+
+
+       self->attr_offset = lseek(fd, 0, SEEK_CUR);
+
+       for (i = 0; i < self->attrs; i++) {
+               attr = self->attr[i];
+
+               f_attr = (struct perf_file_attr){
+                       .attr = attr->attr,
+                       .ids  = {
+                               .offset = attr->id_offset,
+                               .size   = attr->ids * sizeof(u64),
+                       }
+               };
+               do_write(fd, &f_attr, sizeof(f_attr));
+       }
+
+
+       self->data_offset = lseek(fd, 0, SEEK_CUR);
+
+       f_header = (struct perf_file_header){
+               .magic     = PERF_MAGIC,
+               .size      = sizeof(f_header),
+               .attr_size = sizeof(f_attr),
+               .attrs = {
+                       .offset = self->attr_offset,
+                       .size   = self->attrs * sizeof(f_attr),
+               },
+               .data = {
+                       .offset = self->data_offset,
+                       .size   = self->data_size,
+               },
+       };
+
+       lseek(fd, 0, SEEK_SET);
+       do_write(fd, &f_header, sizeof(f_header));
+       lseek(fd, self->data_offset + self->data_size, SEEK_SET);
+
+       self->frozen = 1;
+}
+
+static void do_read(int fd, void *buf, size_t size)
+{
+       while (size) {
+               int ret = read(fd, buf, size);
+
+               if (ret < 0)
+                       die("failed to read");
+
+               size -= ret;
+               buf += ret;
+       }
+}
+
+struct perf_header *perf_header__read(int fd)
+{
+       struct perf_header      *self = perf_header__new();
+       struct perf_file_header f_header;
+       struct perf_file_attr   f_attr;
+       u64                     f_id;
+
+       int nr_attrs, nr_ids, i, j;
+
+       lseek(fd, 0, SEEK_SET);
+       do_read(fd, &f_header, sizeof(f_header));
+
+       if (f_header.magic      != PERF_MAGIC           ||
+           f_header.size       != sizeof(f_header)     ||
+           f_header.attr_size  != sizeof(f_attr))
+               die("incompatible file format");
+
+       nr_attrs = f_header.attrs.size / sizeof(f_attr);
+       lseek(fd, f_header.attrs.offset, SEEK_SET);
+
+       for (i = 0; i < nr_attrs; i++) {
+               struct perf_header_attr *attr;
+               off_t tmp = lseek(fd, 0, SEEK_CUR);
+
+               do_read(fd, &f_attr, sizeof(f_attr));
+
+               attr = perf_header_attr__new(&f_attr.attr);
+
+               nr_ids = f_attr.ids.size / sizeof(u64);
+               lseek(fd, f_attr.ids.offset, SEEK_SET);
+
+               for (j = 0; j < nr_ids; j++) {
+                       do_read(fd, &f_id, sizeof(f_id));
+
+                       perf_header_attr__add_id(attr, f_id);
+               }
+               perf_header__add_attr(self, attr);
+               lseek(fd, tmp, SEEK_SET);
+       }
+
+       self->data_offset = f_header.data.offset;
+       self->data_size   = f_header.data.size;
+
+       lseek(fd, self->data_offset + self->data_size, SEEK_SET);
+
+       self->frozen = 1;
+
+       return self;
+}
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
new file mode 100644 (file)
index 0000000..b5ef53a
--- /dev/null
@@ -0,0 +1,37 @@
+#ifndef _PERF_HEADER_H
+#define _PERF_HEADER_H
+
+#include "../../../include/linux/perf_counter.h"
+#include <sys/types.h>
+#include "types.h"
+
+struct perf_header_attr {
+       struct perf_counter_attr attr;
+       int ids, size;
+       u64 *id;
+       off_t id_offset;
+};
+
+struct perf_header {
+       int frozen;
+       int attrs, size;
+       struct perf_header_attr **attr;
+       off_t attr_offset;
+       u64 data_offset;
+       u64 data_size;
+};
+
+struct perf_header *perf_header__read(int fd);
+void perf_header__write(struct perf_header *self, int fd);
+
+void perf_header__add_attr(struct perf_header *self,
+                          struct perf_header_attr *attr);
+
+struct perf_header_attr *
+perf_header_attr__new(struct perf_counter_attr *attr);
+void perf_header_attr__add_id(struct perf_header_attr *self, u64 id);
+
+
+struct perf_header *perf_header__new(void);
+
+#endif /* _PERF_HEADER_H */
index 6653f7d..17a00e0 100644 (file)
@@ -126,21 +126,6 @@ static int is_executable(const char *name)
            !S_ISREG(st.st_mode))
                return 0;
 
-#ifdef __MINGW32__
-       /* cannot trust the executable bit, peek into the file instead */
-       char buf[3] = { 0 };
-       int n;
-       int fd = open(name, O_RDONLY);
-       st.st_mode &= ~S_IXUSR;
-       if (fd >= 0) {
-               n = read(fd, buf, 2);
-               if (n == 2)
-                       /* DOS executables start with "MZ" */
-                       if (!strcmp(buf, "#!") || !strcmp(buf, "MZ"))
-                               st.st_mode |= S_IXUSR;
-               close(fd);
-       }
-#endif
        return st.st_mode & S_IXUSR;
 }
 
index a28bcca..1915de2 100644 (file)
@@ -9,7 +9,6 @@
 
 static int spawned_pager;
 
-#ifndef __MINGW32__
 static void pager_preexec(void)
 {
        /*
@@ -24,7 +23,6 @@ static void pager_preexec(void)
 
        setenv("LESS", "FRSX", 0);
 }
-#endif
 
 static const char *pager_argv[] = { "sh", "-c", NULL, NULL };
 static struct child_process pager_process;
@@ -70,9 +68,8 @@ void setup_pager(void)
        pager_argv[2] = pager;
        pager_process.argv = pager_argv;
        pager_process.in = -1;
-#ifndef __MINGW32__
        pager_process.preexec_cb = pager_preexec;
-#endif
+
        if (start_command(&pager_process))
                return;
 
index 35d04da..4d042f1 100644 (file)
@@ -16,32 +16,28 @@ struct event_symbol {
        u8      type;
        u64     config;
        char    *symbol;
+       char    *alias;
 };
 
-#define C(x, y) .type = PERF_TYPE_##x, .config = PERF_COUNT_##y
-#define CR(x, y) .type = PERF_TYPE_##x, .config = y
+#define CHW(x) .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_##x
+#define CSW(x) .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_##x
 
 static struct event_symbol event_symbols[] = {
-  { C(HARDWARE, HW_CPU_CYCLES),                "cpu-cycles",           },
-  { C(HARDWARE, HW_CPU_CYCLES),                "cycles",               },
-  { C(HARDWARE, HW_INSTRUCTIONS),      "instructions",         },
-  { C(HARDWARE, HW_CACHE_REFERENCES),  "cache-references",     },
-  { C(HARDWARE, HW_CACHE_MISSES),      "cache-misses",         },
-  { C(HARDWARE, HW_BRANCH_INSTRUCTIONS),"branch-instructions", },
-  { C(HARDWARE, HW_BRANCH_INSTRUCTIONS),"branches",            },
-  { C(HARDWARE, HW_BRANCH_MISSES),     "branch-misses",        },
-  { C(HARDWARE, HW_BUS_CYCLES),                "bus-cycles",           },
-
-  { C(SOFTWARE, SW_CPU_CLOCK),         "cpu-clock",            },
-  { C(SOFTWARE, SW_TASK_CLOCK),                "task-clock",           },
-  { C(SOFTWARE, SW_PAGE_FAULTS),       "page-faults",          },
-  { C(SOFTWARE, SW_PAGE_FAULTS),       "faults",               },
-  { C(SOFTWARE, SW_PAGE_FAULTS_MIN),   "minor-faults",         },
-  { C(SOFTWARE, SW_PAGE_FAULTS_MAJ),   "major-faults",         },
-  { C(SOFTWARE, SW_CONTEXT_SWITCHES),  "context-switches",     },
-  { C(SOFTWARE, SW_CONTEXT_SWITCHES),  "cs",                   },
-  { C(SOFTWARE, SW_CPU_MIGRATIONS),    "cpu-migrations",       },
-  { C(SOFTWARE, SW_CPU_MIGRATIONS),    "migrations",           },
+  { CHW(CPU_CYCLES),           "cpu-cycles",           "cycles"        },
+  { CHW(INSTRUCTIONS),         "instructions",         ""              },
+  { CHW(CACHE_REFERENCES),     "cache-references",     ""              },
+  { CHW(CACHE_MISSES),         "cache-misses",         ""              },
+  { CHW(BRANCH_INSTRUCTIONS),  "branch-instructions",  "branches"      },
+  { CHW(BRANCH_MISSES),                "branch-misses",        ""              },
+  { CHW(BUS_CYCLES),           "bus-cycles",           ""              },
+
+  { CSW(CPU_CLOCK),            "cpu-clock",            ""              },
+  { CSW(TASK_CLOCK),           "task-clock",           ""              },
+  { CSW(PAGE_FAULTS),          "page-faults",          "faults"        },
+  { CSW(PAGE_FAULTS_MIN),      "minor-faults",         ""              },
+  { CSW(PAGE_FAULTS_MAJ),      "major-faults",         ""              },
+  { CSW(CONTEXT_SWITCHES),     "context-switches",     "cs"            },
+  { CSW(CPU_MIGRATIONS),       "cpu-migrations",       "migrations"    },
 };
 
 #define __PERF_COUNTER_FIELD(config, name) \
@@ -74,26 +70,70 @@ static char *sw_event_names[] = {
 
 #define MAX_ALIASES 8
 
-static char *hw_cache [][MAX_ALIASES] = {
      { "L1-data"             , "l1-d", "l1d"                                 },
      { "L1-instruction"      , "l1-i", "l1i"                                 },
      { "L2"                  , "l2"                                          },
      { "Data-TLB"            , "dtlb", "d-tlb"                               },
      { "Instruction-TLB"     , "itlb", "i-tlb"                               },
      { "Branch"              , "bpu" , "btb", "bpc"                          },
+static char *hw_cache[][MAX_ALIASES] = {
{ "L1-d$",    "l1-d",         "l1d",          "L1-data",              },
{ "L1-i$",    "l1-i",         "l1i",          "L1-instruction",       },
{ "LLC",      "L2"                                                    },
{ "dTLB",     "d-tlb",        "Data-TLB",                             },
{ "iTLB",     "i-tlb",        "Instruction-TLB",                      },
{ "branch",   "branches",     "bpu",          "btb",          "bpc",  },
 };
 
-static char *hw_cache_op [][MAX_ALIASES] = {
      { "Load"                , "read"                                        },
      { "Store"               , "write"                                       },
      { "Prefetch"            , "speculative-read", "speculative-load"        },
+static char *hw_cache_op[][MAX_ALIASES] = {
{ "load",     "loads",        "read",                                 },
{ "store",    "stores",       "write",                                },
{ "prefetch", "prefetches",   "speculative-read", "speculative-load", },
 };
 
-static char *hw_cache_result [][MAX_ALIASES] = {
      { "Reference"           , "ops", "access"                               },
      { "Miss"                                                                },
+static char *hw_cache_result[][MAX_ALIASES] = {
{ "refs",     "Reference",    "ops",          "access",               },
{ "misses",   "miss",                                                 },
 };
 
+#define C(x)           PERF_COUNT_HW_CACHE_##x
+#define CACHE_READ     (1 << C(OP_READ))
+#define CACHE_WRITE    (1 << C(OP_WRITE))
+#define CACHE_PREFETCH (1 << C(OP_PREFETCH))
+#define COP(x)         (1 << x)
+
+/*
+ * cache operartion stat
+ * L1I : Read and prefetch only
+ * ITLB and BPU : Read-only
+ */
+static unsigned long hw_cache_stat[C(MAX)] = {
+ [C(L1D)]      = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH),
+ [C(L1I)]      = (CACHE_READ | CACHE_PREFETCH),
+ [C(LL)]       = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH),
+ [C(DTLB)]     = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH),
+ [C(ITLB)]     = (CACHE_READ),
+ [C(BPU)]      = (CACHE_READ),
+};
+
+static int is_cache_op_valid(u8 cache_type, u8 cache_op)
+{
+       if (hw_cache_stat[cache_type] & COP(cache_op))
+               return 1;       /* valid */
+       else
+               return 0;       /* invalid */
+}
+
+static char *event_cache_name(u8 cache_type, u8 cache_op, u8 cache_result)
+{
+       static char name[50];
+
+       if (cache_result) {
+               sprintf(name, "%s-%s-%s", hw_cache[cache_type][0],
+                       hw_cache_op[cache_op][0],
+                       hw_cache_result[cache_result][0]);
+       } else {
+               sprintf(name, "%s-%s", hw_cache[cache_type][0],
+                       hw_cache_op[cache_op][1]);
+       }
+
+       return name;
+}
+
 char *event_name(int counter)
 {
        u64 config = attrs[counter].config;
@@ -113,7 +153,6 @@ char *event_name(int counter)
 
        case PERF_TYPE_HW_CACHE: {
                u8 cache_type, cache_op, cache_result;
-               static char name[100];
 
                cache_type   = (config >>  0) & 0xff;
                if (cache_type > PERF_COUNT_HW_CACHE_MAX)
@@ -127,12 +166,10 @@ char *event_name(int counter)
                if (cache_result > PERF_COUNT_HW_CACHE_RESULT_MAX)
                        return "unknown-ext-hardware-cache-result";
 
-               sprintf(name, "%s-Cache-%s-%ses",
-                       hw_cache[cache_type][0],
-                       hw_cache_op[cache_op][0],
-                       hw_cache_result[cache_result][0]);
+               if (!is_cache_op_valid(cache_type, cache_op))
+                       return "invalid-cache";
 
-               return name;
+               return event_cache_name(cache_type, cache_op, cache_result);
        }
 
        case PERF_TYPE_SOFTWARE:
@@ -163,7 +200,8 @@ static int parse_aliases(const char *str, char *names[][MAX_ALIASES], int size)
        return -1;
 }
 
-static int parse_generic_hw_symbols(const char *str, struct perf_counter_attr *attr)
+static int
+parse_generic_hw_symbols(const char *str, struct perf_counter_attr *attr)
 {
        int cache_type = -1, cache_op = 0, cache_result = 0;
 
@@ -182,6 +220,9 @@ static int parse_generic_hw_symbols(const char *str, struct perf_counter_attr *a
        if (cache_op == -1)
                cache_op = PERF_COUNT_HW_CACHE_OP_READ;
 
+       if (!is_cache_op_valid(cache_type, cache_op))
+               return -EINVAL;
+
        cache_result = parse_aliases(str, hw_cache_result,
                                        PERF_COUNT_HW_CACHE_RESULT_MAX);
        /*
@@ -196,6 +237,19 @@ static int parse_generic_hw_symbols(const char *str, struct perf_counter_attr *a
        return 0;
 }
 
+static int check_events(const char *str, unsigned int i)
+{
+       if (!strncmp(str, event_symbols[i].symbol,
+                    strlen(event_symbols[i].symbol)))
+               return 1;
+
+       if (strlen(event_symbols[i].alias))
+               if (!strncmp(str, event_symbols[i].alias,
+                            strlen(event_symbols[i].alias)))
+                       return 1;
+       return 0;
+}
+
 /*
  * Each event can have multiple symbolic names.
  * Symbolic names are (almost) exactly matched.
@@ -235,9 +289,7 @@ static int parse_event_symbols(const char *str, struct perf_counter_attr *attr)
        }
 
        for (i = 0; i < ARRAY_SIZE(event_symbols); i++) {
-               if (!strncmp(str, event_symbols[i].symbol,
-                            strlen(event_symbols[i].symbol))) {
-
+               if (check_events(str, i)) {
                        attr->type = event_symbols[i].type;
                        attr->config = event_symbols[i].config;
 
@@ -289,6 +341,7 @@ void print_events(void)
 {
        struct event_symbol *syms = event_symbols;
        unsigned int i, type, prev_type = -1;
+       char name[40];
 
        fprintf(stderr, "\n");
        fprintf(stderr, "List of pre-defined events (to be used in -e):\n");
@@ -301,14 +354,18 @@ void print_events(void)
                if (type != prev_type)
                        fprintf(stderr, "\n");
 
-               fprintf(stderr, "  %-30s [%s]\n", syms->symbol,
+               if (strlen(syms->alias))
+                       sprintf(name, "%s OR %s", syms->symbol, syms->alias);
+               else
+                       strcpy(name, syms->symbol);
+               fprintf(stderr, "  %-40s [%s]\n", name,
                        event_type_descriptors[type]);
 
                prev_type = type;
        }
 
        fprintf(stderr, "\n");
-       fprintf(stderr, "  %-30s [raw hardware event descriptor]\n",
+       fprintf(stderr, "  %-40s [raw hardware event descriptor]\n",
                "rNNN");
        fprintf(stderr, "\n");
 
index b2f5e85..a393534 100644 (file)
@@ -65,7 +65,6 @@ int start_command(struct child_process *cmd)
                cmd->err = fderr[0];
        }
 
-#ifndef __MINGW32__
        fflush(NULL);
        cmd->pid = fork();
        if (!cmd->pid) {
@@ -118,71 +117,6 @@ int start_command(struct child_process *cmd)
                }
                exit(127);
        }
-#else
-       int s0 = -1, s1 = -1, s2 = -1;  /* backups of stdin, stdout, stderr */
-       const char **sargv = cmd->argv;
-       char **env = environ;
-
-       if (cmd->no_stdin) {
-               s0 = dup(0);
-               dup_devnull(0);
-       } else if (need_in) {
-               s0 = dup(0);
-               dup2(fdin[0], 0);
-       } else if (cmd->in) {
-               s0 = dup(0);
-               dup2(cmd->in, 0);
-       }
-
-       if (cmd->no_stderr) {
-               s2 = dup(2);
-               dup_devnull(2);
-       } else if (need_err) {
-               s2 = dup(2);
-               dup2(fderr[1], 2);
-       }
-
-       if (cmd->no_stdout) {
-               s1 = dup(1);
-               dup_devnull(1);
-       } else if (cmd->stdout_to_stderr) {
-               s1 = dup(1);
-               dup2(2, 1);
-       } else if (need_out) {
-               s1 = dup(1);
-               dup2(fdout[1], 1);
-       } else if (cmd->out > 1) {
-               s1 = dup(1);
-               dup2(cmd->out, 1);
-       }
-
-       if (cmd->dir)
-               die("chdir in start_command() not implemented");
-       if (cmd->env) {
-               env = copy_environ();
-               for (; *cmd->env; cmd->env++)
-                       env = env_setenv(env, *cmd->env);
-       }
-
-       if (cmd->perf_cmd) {
-               cmd->argv = prepare_perf_cmd(cmd->argv);
-       }
-
-       cmd->pid = mingw_spawnvpe(cmd->argv[0], cmd->argv, env);
-
-       if (cmd->env)
-               free_environ(env);
-       if (cmd->perf_cmd)
-               free(cmd->argv);
-
-       cmd->argv = sargv;
-       if (s0 >= 0)
-               dup2(s0, 0), close(s0);
-       if (s1 >= 0)
-               dup2(s1, 1), close(s1);
-       if (s2 >= 0)
-               dup2(s2, 2), close(s2);
-#endif
 
        if (cmd->pid < 0) {
                int err = errno;
@@ -288,14 +222,6 @@ int run_command_v_opt_cd_env(const char **argv, int opt, const char *dir, const
        return run_command(&cmd);
 }
 
-#ifdef __MINGW32__
-static __stdcall unsigned run_thread(void *data)
-{
-       struct async *async = data;
-       return async->proc(async->fd_for_proc, async->data);
-}
-#endif
-
 int start_async(struct async *async)
 {
        int pipe_out[2];
@@ -304,7 +230,6 @@ int start_async(struct async *async)
                return error("cannot create pipe: %s", strerror(errno));
        async->out = pipe_out[0];
 
-#ifndef __MINGW32__
        /* Flush stdio before fork() to avoid cloning buffers */
        fflush(NULL);
 
@@ -319,33 +244,17 @@ int start_async(struct async *async)
                exit(!!async->proc(pipe_out[1], async->data));
        }
        close(pipe_out[1]);
-#else
-       async->fd_for_proc = pipe_out[1];
-       async->tid = (HANDLE) _beginthreadex(NULL, 0, run_thread, async, 0, NULL);
-       if (!async->tid) {
-               error("cannot create thread: %s", strerror(errno));
-               close_pair(pipe_out);
-               return -1;
-       }
-#endif
+
        return 0;
 }
 
 int finish_async(struct async *async)
 {
-#ifndef __MINGW32__
        int ret = 0;
 
        if (wait_or_whine(async->pid))
                ret = error("waitpid (async) failed");
-#else
-       DWORD ret = 0;
-       if (WaitForSingleObject(async->tid, INFINITE) != WAIT_OBJECT_0)
-               ret = error("waiting for thread failed: %lu", GetLastError());
-       else if (!GetExitCodeThread(async->tid, &ret))
-               ret = error("cannot get thread exit code: %lu", GetLastError());
-       CloseHandle(async->tid);
-#endif
+
        return ret;
 }
 
index 328289f..cc1837d 100644 (file)
@@ -79,12 +79,7 @@ struct async {
        int (*proc)(int fd, void *data);
        void *data;
        int out;        /* caller reads from here and closes it */
-#ifndef __MINGW32__
        pid_t pid;
-#else
-       HANDLE tid;
-       int fd_for_proc;
-#endif
 };
 
 int start_async(struct async *async);
index eaba093..464e7ca 100644 (file)
@@ -259,7 +259,7 @@ size_t strbuf_fread(struct strbuf *sb, size_t size, FILE *f)
        res = fread(sb->buf + sb->len, 1, size, f);
        if (res > 0)
                strbuf_setlen(sb, sb->len + res);
-       else if (res < 0 && oldalloc == 0)
+       else if (oldalloc == 0)
                strbuf_release(sb);
        return res;
 }
index 37b0325..3dca2f6 100644 (file)
@@ -1,7 +1,7 @@
 #ifndef _PERF_STRING_H_
 #define _PERF_STRING_H_
 
-#include "../types.h"
+#include "types.h"
 
 int hex2u64(const char *ptr, u64 *val);
 
diff --git a/tools/perf/util/strlist.c b/tools/perf/util/strlist.c
new file mode 100644 (file)
index 0000000..025a78e
--- /dev/null
@@ -0,0 +1,184 @@
+/*
+ * (c) 2009 Arnaldo Carvalho de Melo <acme@redhat.com>
+ *
+ * Licensed under the GPLv2.
+ */
+
+#include "strlist.h"
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+static struct str_node *str_node__new(const char *s, bool dupstr)
+{
+       struct str_node *self = malloc(sizeof(*self));
+
+       if (self != NULL) {
+               if (dupstr) {
+                       s = strdup(s);
+                       if (s == NULL)
+                               goto out_delete;
+               }
+               self->s = s;
+       }
+
+       return self;
+
+out_delete:
+       free(self);
+       return NULL;
+}
+
+static void str_node__delete(struct str_node *self, bool dupstr)
+{
+       if (dupstr)
+               free((void *)self->s);
+       free(self);
+}
+
+int strlist__add(struct strlist *self, const char *new_entry)
+{
+       struct rb_node **p = &self->entries.rb_node;
+       struct rb_node *parent = NULL;
+       struct str_node *sn;
+
+       while (*p != NULL) {
+               int rc;
+
+               parent = *p;
+               sn = rb_entry(parent, struct str_node, rb_node);
+               rc = strcmp(sn->s, new_entry);
+
+               if (rc > 0)
+                       p = &(*p)->rb_left;
+               else if (rc < 0)
+                       p = &(*p)->rb_right;
+               else
+                       return -EEXIST;
+       }
+
+       sn = str_node__new(new_entry, self->dupstr);
+       if (sn == NULL)
+               return -ENOMEM;
+
+       rb_link_node(&sn->rb_node, parent, p);
+       rb_insert_color(&sn->rb_node, &self->entries);
+
+       return 0;
+}
+
+int strlist__load(struct strlist *self, const char *filename)
+{
+       char entry[1024];
+       int err;
+       FILE *fp = fopen(filename, "r");
+
+       if (fp == NULL)
+               return errno;
+
+       while (fgets(entry, sizeof(entry), fp) != NULL) {
+               const size_t len = strlen(entry);
+
+               if (len == 0)
+                       continue;
+               entry[len - 1] = '\0';
+
+               err = strlist__add(self, entry);
+               if (err != 0)
+                       goto out;
+       }
+
+       err = 0;
+out:
+       fclose(fp);
+       return err;
+}
+
+void strlist__remove(struct strlist *self, struct str_node *sn)
+{
+       rb_erase(&sn->rb_node, &self->entries);
+       str_node__delete(sn, self->dupstr);
+}
+
+bool strlist__has_entry(struct strlist *self, const char *entry)
+{
+       struct rb_node **p = &self->entries.rb_node;
+       struct rb_node *parent = NULL;
+
+       while (*p != NULL) {
+               struct str_node *sn;
+               int rc;
+
+               parent = *p;
+               sn = rb_entry(parent, struct str_node, rb_node);
+               rc = strcmp(sn->s, entry);
+
+               if (rc > 0)
+                       p = &(*p)->rb_left;
+               else if (rc < 0)
+                       p = &(*p)->rb_right;
+               else
+                       return true;
+       }
+
+       return false;
+}
+
+static int strlist__parse_list_entry(struct strlist *self, const char *s)
+{
+       if (strncmp(s, "file://", 7) == 0)
+               return strlist__load(self, s + 7);
+
+       return strlist__add(self, s);
+}
+
+int strlist__parse_list(struct strlist *self, const char *s)
+{
+       char *sep;
+       int err;
+
+       while ((sep = strchr(s, ',')) != NULL) {
+               *sep = '\0';
+               err = strlist__parse_list_entry(self, s);
+               *sep = ',';
+               if (err != 0)
+                       return err;
+               s = sep + 1;
+       }
+
+       return *s ? strlist__parse_list_entry(self, s) : 0;
+}
+
+struct strlist *strlist__new(bool dupstr, const char *slist)
+{
+       struct strlist *self = malloc(sizeof(*self));
+
+       if (self != NULL) {
+               self->entries = RB_ROOT;
+               self->dupstr = dupstr;
+               if (slist && strlist__parse_list(self, slist) != 0)
+                       goto out_error;
+       }
+
+       return self;
+out_error:
+       free(self);
+       return NULL;
+}
+
+void strlist__delete(struct strlist *self)
+{
+       if (self != NULL) {
+               struct str_node *pos;
+               struct rb_node *next = rb_first(&self->entries);
+
+               while (next) {
+                       pos = rb_entry(next, struct str_node, rb_node);
+                       next = rb_next(&pos->rb_node);
+                       strlist__remove(self, pos);
+               }
+               self->entries = RB_ROOT;
+               free(self);
+       }
+}
diff --git a/tools/perf/util/strlist.h b/tools/perf/util/strlist.h
new file mode 100644 (file)
index 0000000..2fb117f
--- /dev/null
@@ -0,0 +1,32 @@
+#ifndef STRLIST_H_
+#define STRLIST_H_
+
+#include "rbtree.h"
+#include <stdbool.h>
+
+struct str_node {
+       struct rb_node rb_node;
+       const char     *s;
+};
+
+struct strlist {
+       struct rb_root entries;
+       bool dupstr;
+};
+
+struct strlist *strlist__new(bool dupstr, const char *slist);
+void strlist__delete(struct strlist *self);
+
+void strlist__remove(struct strlist *self, struct str_node *sn);
+int strlist__load(struct strlist *self, const char *filename);
+int strlist__add(struct strlist *self, const char *str);
+
+bool strlist__has_entry(struct strlist *self, const char *entry);
+
+static inline bool strlist__empty(const struct strlist *self)
+{
+       return rb_first(&self->entries) == NULL;
+}
+
+int strlist__parse_list(struct strlist *self, const char *s);
+#endif /* STRLIST_H_ */
index 86e1437..78c2efd 100644 (file)
@@ -520,7 +520,9 @@ static int dso__load_sym(struct dso *self, int fd, const char *name,
        nr_syms = shdr.sh_size / shdr.sh_entsize;
 
        memset(&sym, 0, sizeof(sym));
-
+       self->prelinked = elf_section_by_name(elf, &ehdr, &shdr,
+                                             ".gnu.prelink_undo",
+                                             NULL) != NULL;
        elf_symtab__for_each_symbol(syms, nr_syms, index, sym) {
                struct symbol *f;
                u64 obj_start;
@@ -535,7 +537,13 @@ static int dso__load_sym(struct dso *self, int fd, const char *name,
                gelf_getshdr(sec, &shdr);
                obj_start = sym.st_value;
 
-               sym.st_value -= shdr.sh_addr - shdr.sh_offset;
+               if (self->prelinked) {
+                       if (verbose >= 2)
+                               printf("adjusting symbol: st_value: %Lx sh_addr: %Lx sh_offset: %Lx\n",
+                                       (u64)sym.st_value, (u64)shdr.sh_addr, (u64)shdr.sh_offset);
+
+                       sym.st_value -= shdr.sh_addr - shdr.sh_offset;
+               }
 
                f = symbol__new(sym.st_value, sym.st_size,
                                elf_sym__name(&sym, symstrs),
@@ -569,6 +577,8 @@ int dso__load(struct dso *self, symbol_filter_t filter, int verbose)
        if (!name)
                return -1;
 
+       self->prelinked = 0;
+
        if (strncmp(self->name, "/tmp/perf-", 10) == 0)
                return dso__load_perf_map(self, filter, verbose);
 
@@ -629,7 +639,7 @@ int dso__load_kernel(struct dso *self, const char *vmlinux,
        if (vmlinux)
                err = dso__load_vmlinux(self, vmlinux, filter, verbose);
 
-       if (err)
+       if (err < 0)
                err = dso__load_kallsyms(self, filter, verbose);
 
        return err;
index ea332e5..2c48ace 100644 (file)
@@ -2,7 +2,7 @@
 #define _PERF_SYMBOL_ 1
 
 #include <linux/types.h>
-#include "../types.h"
+#include "types.h"
 #include "list.h"
 #include "rbtree.h"
 
@@ -20,8 +20,9 @@ struct symbol {
 struct dso {
        struct list_head node;
        struct rb_root   syms;
-       unsigned int     sym_priv_size;
        struct symbol    *(*find_symbol)(struct dso *, u64 ip);
+       unsigned int     sym_priv_size;
+       unsigned char    prelinked;
        char             name[0];
 };
 
similarity index 100%
rename from tools/perf/types.h
rename to tools/perf/util/types.h
index b8cfed7..b4be607 100644 (file)
@@ -67,7 +67,6 @@
 #include <assert.h>
 #include <regex.h>
 #include <utime.h>
-#ifndef __MINGW32__
 #include <sys/wait.h>
 #include <sys/poll.h>
 #include <sys/socket.h>
 #include <netdb.h>
 #include <pwd.h>
 #include <inttypes.h>
-#if defined(__CYGWIN__)
-#undef _XOPEN_SOURCE
-#include <grp.h>
-#define _XOPEN_SOURCE 600
-#include "compat/cygwin.h"
-#else
-#undef _ALL_SOURCE /* AIX 5.3L defines a struct list with _ALL_SOURCE. */
-#include <grp.h>
-#define _ALL_SOURCE 1
-#endif
-#else  /* __MINGW32__ */
-/* pull in Windows compatibility stuff */
-#include "compat/mingw.h"
-#endif /* __MINGW32__ */
 
 #ifndef NO_ICONV
 #include <iconv.h>
index 7645543..2884baf 100644 (file)
@@ -746,6 +746,7 @@ static bool make_all_cpus_request(struct kvm *kvm, unsigned int req)
                cpumask_clear(cpus);
 
        me = get_cpu();
+       spin_lock(&kvm->requests_lock);
        for (i = 0; i < KVM_MAX_VCPUS; ++i) {
                vcpu = kvm->vcpus[i];
                if (!vcpu)
@@ -762,6 +763,7 @@ static bool make_all_cpus_request(struct kvm *kvm, unsigned int req)
                smp_call_function_many(cpus, ack_flush, NULL, 1);
        else
                called = false;
+       spin_unlock(&kvm->requests_lock);
        put_cpu();
        free_cpumask_var(cpus);
        return called;
@@ -982,6 +984,7 @@ static struct kvm *kvm_create_vm(void)
        kvm->mm = current->mm;
        atomic_inc(&kvm->mm->mm_count);
        spin_lock_init(&kvm->mmu_lock);
+       spin_lock_init(&kvm->requests_lock);
        kvm_io_bus_init(&kvm->pio_bus);
        mutex_init(&kvm->lock);
        kvm_io_bus_init(&kvm->mmio_bus);
@@ -1194,6 +1197,8 @@ int __kvm_set_memory_region(struct kvm *kvm,
                if (!new.dirty_bitmap)
                        goto out_free;
                memset(new.dirty_bitmap, 0, dirty_bytes);
+               if (old.npages)
+                       kvm_arch_flush_shadow(kvm);
        }
 #endif /* not defined CONFIG_S390 */